xref: /reactos/dll/win32/vbscript/vbscript.c (revision cdf90707)
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 IActiveScriptDebugVtbl IActiveScriptDebug64Vtbl
33 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
34 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_64Vtbl
35 
36 #else
37 
38 #define CTXARG_T DWORD
39 #define IActiveScriptDebugVtbl IActiveScriptDebug32Vtbl
40 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
41 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_32Vtbl
42 
43 #endif
44 
45 struct VBScript {
46     IActiveScript IActiveScript_iface;
47     IActiveScriptDebug IActiveScriptDebug_iface;
48     IActiveScriptParse IActiveScriptParse_iface;
49     IActiveScriptParseProcedure2 IActiveScriptParseProcedure2_iface;
50     IObjectSafety IObjectSafety_iface;
51 
52     LONG ref;
53 
54     SCRIPTSTATE state;
55     script_ctx_t *ctx;
56     LONG thread_id;
57     BOOL is_initialized;
58 };
59 
60 typedef struct {
61     IActiveScriptError IActiveScriptError_iface;
62     LONG ref;
63     EXCEPINFO ei;
64 } VBScriptError;
65 
66 static void change_state(VBScript *This, SCRIPTSTATE state)
67 {
68     if(This->state == state)
69         return;
70 
71     This->state = state;
72     if(This->ctx->site)
73         IActiveScriptSite_OnStateChange(This->ctx->site, state);
74 }
75 
76 static inline BOOL is_started(VBScript *This)
77 {
78     return This->state == SCRIPTSTATE_STARTED
79         || This->state == SCRIPTSTATE_CONNECTED
80         || This->state == SCRIPTSTATE_DISCONNECTED;
81 }
82 
83 static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res)
84 {
85     code->pending_exec = FALSE;
86     return exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res);
87 }
88 
89 static void exec_queued_code(script_ctx_t *ctx)
90 {
91     vbscode_t *iter;
92 
93     LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) {
94         if(iter->pending_exec)
95             exec_global_code(ctx, iter, NULL);
96     }
97 }
98 
99 IDispatch *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags)
100 {
101     named_item_t *item;
102     HRESULT hres;
103 
104     LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) {
105         if((item->flags & flags) == flags && !wcsicmp(item->name, name)) {
106             if(!item->disp) {
107                 IUnknown *unk;
108 
109                 hres = IActiveScriptSite_GetItemInfo(ctx->site, item->name,
110                                                      SCRIPTINFO_IUNKNOWN, &unk, NULL);
111                 if(FAILED(hres)) {
112                     WARN("GetItemInfo failed: %08x\n", hres);
113                     continue;
114                 }
115 
116                 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
117                 IUnknown_Release(unk);
118                 if(FAILED(hres)) {
119                     WARN("object does not implement IDispatch\n");
120                     continue;
121                 }
122             }
123 
124             return item->disp;
125         }
126     }
127 
128     return NULL;
129 }
130 
131 static void release_script(script_ctx_t *ctx)
132 {
133     class_desc_t *class_desc;
134 
135     collect_objects(ctx);
136     clear_ei(&ctx->ei);
137 
138     release_dynamic_vars(ctx->global_vars);
139     ctx->global_vars = NULL;
140 
141     while(!list_empty(&ctx->named_items)) {
142         named_item_t *iter = LIST_ENTRY(list_head(&ctx->named_items), named_item_t, entry);
143 
144         list_remove(&iter->entry);
145         if(iter->disp)
146             IDispatch_Release(iter->disp);
147         heap_free(iter->name);
148         heap_free(iter);
149     }
150 
151     while(ctx->procs) {
152         class_desc = ctx->procs;
153         ctx->procs = class_desc->next;
154 
155         heap_free(class_desc);
156     }
157 
158     if(ctx->host_global) {
159         IDispatch_Release(ctx->host_global);
160         ctx->host_global = NULL;
161     }
162 
163     if(ctx->secmgr) {
164         IInternetHostSecurityManager_Release(ctx->secmgr);
165         ctx->secmgr = NULL;
166     }
167 
168     if(ctx->site) {
169         IActiveScriptSite_Release(ctx->site);
170         ctx->site = NULL;
171     }
172 
173     if(ctx->script_obj) {
174         ScriptDisp *script_obj = ctx->script_obj;
175 
176         ctx->script_obj = NULL;
177         script_obj->ctx = NULL;
178         IDispatchEx_Release(&script_obj->IDispatchEx_iface);
179     }
180 
181     detach_global_objects(ctx);
182     heap_pool_free(&ctx->heap);
183     heap_pool_init(&ctx->heap);
184 }
185 
186 static void destroy_script(script_ctx_t *ctx)
187 {
188     while(!list_empty(&ctx->code_list))
189         release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry));
190 
191     release_script(ctx);
192     heap_free(ctx);
193 }
194 
195 static void decrease_state(VBScript *This, SCRIPTSTATE state)
196 {
197     switch(This->state) {
198     case SCRIPTSTATE_CONNECTED:
199         change_state(This, SCRIPTSTATE_DISCONNECTED);
200         if(state == SCRIPTSTATE_DISCONNECTED)
201             return;
202         /* FALLTHROUGH */
203     case SCRIPTSTATE_STARTED:
204     case SCRIPTSTATE_DISCONNECTED:
205         if(This->state == SCRIPTSTATE_DISCONNECTED)
206             change_state(This, SCRIPTSTATE_INITIALIZED);
207         if(state == SCRIPTSTATE_INITIALIZED)
208             break;
209         /* FALLTHROUGH */
210     case SCRIPTSTATE_INITIALIZED:
211     case SCRIPTSTATE_UNINITIALIZED:
212         change_state(This, state);
213         release_script(This->ctx);
214         This->thread_id = 0;
215         break;
216     case SCRIPTSTATE_CLOSED:
217         break;
218     DEFAULT_UNREACHABLE;
219     }
220 }
221 
222 static inline VBScriptError *impl_from_IActiveScriptError(IActiveScriptError *iface)
223 {
224     return CONTAINING_RECORD(iface, VBScriptError, IActiveScriptError_iface);
225 }
226 
227 static HRESULT WINAPI VBScriptError_QueryInterface(IActiveScriptError *iface, REFIID riid, void **ppv)
228 {
229     VBScriptError *This = impl_from_IActiveScriptError(iface);
230 
231     if(IsEqualGUID(riid, &IID_IUnknown)) {
232         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
233         *ppv = &This->IActiveScriptError_iface;
234     }else if(IsEqualGUID(riid, &IID_IActiveScriptError)) {
235         TRACE("(%p)->(IID_IActiveScriptError %p)\n", This, ppv);
236         *ppv = &This->IActiveScriptError_iface;
237     }else {
238         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
239         *ppv = NULL;
240         return E_NOINTERFACE;
241     }
242 
243     IUnknown_AddRef((IUnknown*)*ppv);
244     return S_OK;
245 }
246 
247 static ULONG WINAPI VBScriptError_AddRef(IActiveScriptError *iface)
248 {
249     VBScriptError *This = impl_from_IActiveScriptError(iface);
250     LONG ref = InterlockedIncrement(&This->ref);
251 
252     TRACE("(%p) ref=%d\n", This, ref);
253 
254     return ref;
255 }
256 
257 static ULONG WINAPI VBScriptError_Release(IActiveScriptError *iface)
258 {
259     VBScriptError *This = impl_from_IActiveScriptError(iface);
260     LONG ref = InterlockedDecrement(&This->ref);
261 
262     TRACE("(%p) ref=%d\n", This, ref);
263 
264     if(!ref) {
265         heap_free(This);
266     }
267 
268     return ref;
269 }
270 
271 static HRESULT WINAPI VBScriptError_GetExceptionInfo(IActiveScriptError *iface, EXCEPINFO *excepinfo)
272 {
273     VBScriptError *This = impl_from_IActiveScriptError(iface);
274 
275     TRACE("(%p)->(%p)\n", This, excepinfo);
276 
277     *excepinfo = This->ei;
278     excepinfo->bstrSource = SysAllocString(This->ei.bstrSource);
279     excepinfo->bstrDescription = SysAllocString(This->ei.bstrDescription);
280     excepinfo->bstrHelpFile = SysAllocString(This->ei.bstrHelpFile);
281     return S_OK;
282 }
283 
284 static HRESULT WINAPI VBScriptError_GetSourcePosition(IActiveScriptError *iface, DWORD *source_context, ULONG *line, LONG *character)
285 {
286     VBScriptError *This = impl_from_IActiveScriptError(iface);
287 
288     FIXME("(%p)->(%p %p %p)\n", This, source_context, line, character);
289 
290     if(source_context)
291         *source_context = 0;
292     if(line)
293         *line = 0;
294     if(character)
295         *character = 0;
296     return S_OK;
297 }
298 
299 static HRESULT WINAPI VBScriptError_GetSourceLineText(IActiveScriptError *iface, BSTR *source)
300 {
301     VBScriptError *This = impl_from_IActiveScriptError(iface);
302     FIXME("(%p)->(%p)\n", This, source);
303     return E_NOTIMPL;
304 }
305 
306 static const IActiveScriptErrorVtbl VBScriptErrorVtbl = {
307     VBScriptError_QueryInterface,
308     VBScriptError_AddRef,
309     VBScriptError_Release,
310     VBScriptError_GetExceptionInfo,
311     VBScriptError_GetSourcePosition,
312     VBScriptError_GetSourceLineText
313 };
314 
315 HRESULT report_script_error(script_ctx_t *ctx)
316 {
317     VBScriptError *error;
318     HRESULT hres, result;
319 
320     if(!(error = heap_alloc(sizeof(*error))))
321         return E_OUTOFMEMORY;
322     error->IActiveScriptError_iface.lpVtbl = &VBScriptErrorVtbl;
323 
324     error->ref = 1;
325     error->ei = ctx->ei;
326     memset(&ctx->ei, 0, sizeof(ctx->ei));
327     result = error->ei.scode;
328 
329     hres = IActiveScriptSite_OnScriptError(ctx->site, &error->IActiveScriptError_iface);
330     IActiveScriptError_Release(&error->IActiveScriptError_iface);
331     return hres == S_OK ? SCRIPT_E_REPORTED : result;
332 }
333 
334 static inline VBScript *impl_from_IActiveScript(IActiveScript *iface)
335 {
336     return CONTAINING_RECORD(iface, VBScript, IActiveScript_iface);
337 }
338 
339 static HRESULT WINAPI VBScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
340 {
341     VBScript *This = impl_from_IActiveScript(iface);
342 
343     if(IsEqualGUID(riid, &IID_IUnknown)) {
344         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
345         *ppv = &This->IActiveScript_iface;
346     }else if(IsEqualGUID(riid, &IID_IActiveScript)) {
347         TRACE("(%p)->(IID_IActiveScript %p)\n", This, ppv);
348         *ppv = &This->IActiveScript_iface;
349     }else if(IsEqualGUID(riid, &IID_IActiveScriptDebug)) {
350         TRACE("(%p)->(IID_IActiveScriptDebug %p)\n", This, ppv);
351         *ppv = &This->IActiveScriptDebug_iface;
352     }else if(IsEqualGUID(riid, &IID_IActiveScriptParse)) {
353         TRACE("(%p)->(IID_IActiveScriptParse %p)\n", This, ppv);
354         *ppv = &This->IActiveScriptParse_iface;
355     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure2)) {
356         TRACE("(%p)->(IID_IActiveScriptParseProcedure2 %p)\n", This, ppv);
357         *ppv = &This->IActiveScriptParseProcedure2_iface;
358     }else if(IsEqualGUID(riid, &IID_IObjectSafety)) {
359         TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv);
360         *ppv = &This->IObjectSafety_iface;
361     }else {
362         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
363         *ppv = NULL;
364         return E_NOINTERFACE;
365     }
366 
367     IUnknown_AddRef((IUnknown*)*ppv);
368     return S_OK;
369 }
370 
371 static ULONG WINAPI VBScript_AddRef(IActiveScript *iface)
372 {
373     VBScript *This = impl_from_IActiveScript(iface);
374     LONG ref = InterlockedIncrement(&This->ref);
375 
376     TRACE("(%p) ref=%d\n", This, ref);
377 
378     return ref;
379 }
380 
381 static ULONG WINAPI VBScript_Release(IActiveScript *iface)
382 {
383     VBScript *This = impl_from_IActiveScript(iface);
384     LONG ref = InterlockedDecrement(&This->ref);
385 
386     TRACE("(%p) ref=%d\n", iface, ref);
387 
388     if(!ref) {
389         decrease_state(This, SCRIPTSTATE_CLOSED);
390         destroy_script(This->ctx);
391         heap_free(This);
392     }
393 
394     return ref;
395 }
396 
397 static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
398 {
399     VBScript *This = impl_from_IActiveScript(iface);
400     LCID lcid;
401     HRESULT hres;
402 
403     TRACE("(%p)->(%p)\n", This, pass);
404 
405     if(!pass)
406         return E_POINTER;
407 
408     if(This->ctx->site)
409         return E_UNEXPECTED;
410 
411     if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0))
412         return E_UNEXPECTED;
413 
414     hres = create_script_disp(This->ctx, &This->ctx->script_obj);
415     if(FAILED(hres))
416         return hres;
417 
418     This->ctx->site = pass;
419     IActiveScriptSite_AddRef(This->ctx->site);
420 
421     hres = IActiveScriptSite_GetLCID(This->ctx->site, &lcid);
422     if(hres == S_OK)
423         This->ctx->lcid = lcid;
424 
425     if(This->is_initialized)
426         change_state(This, SCRIPTSTATE_INITIALIZED);
427     return S_OK;
428 }
429 
430 static HRESULT WINAPI VBScript_GetScriptSite(IActiveScript *iface, REFIID riid,
431                                             void **ppvObject)
432 {
433     VBScript *This = impl_from_IActiveScript(iface);
434     FIXME("(%p)->()\n", This);
435     return E_NOTIMPL;
436 }
437 
438 static HRESULT WINAPI VBScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
439 {
440     VBScript *This = impl_from_IActiveScript(iface);
441 
442     TRACE("(%p)->(%d)\n", This, ss);
443 
444     if(This->thread_id && GetCurrentThreadId() != This->thread_id)
445         return E_UNEXPECTED;
446 
447     if(ss == SCRIPTSTATE_UNINITIALIZED) {
448         if(This->state == SCRIPTSTATE_CLOSED)
449             return E_UNEXPECTED;
450 
451         decrease_state(This, SCRIPTSTATE_UNINITIALIZED);
452         return S_OK;
453     }
454 
455     if(!This->is_initialized)
456         return E_UNEXPECTED;
457 
458     switch(ss) {
459     case SCRIPTSTATE_STARTED:
460     case SCRIPTSTATE_CONNECTED: /* FIXME */
461         if(This->state == SCRIPTSTATE_CLOSED)
462             return E_UNEXPECTED;
463 
464         exec_queued_code(This->ctx);
465         break;
466     case SCRIPTSTATE_INITIALIZED:
467         FIXME("unimplemented SCRIPTSTATE_INITIALIZED\n");
468         return S_OK;
469     case SCRIPTSTATE_DISCONNECTED:
470         FIXME("unimplemented SCRIPTSTATE_DISCONNECTED\n");
471         return S_OK;
472     default:
473         FIXME("unimplemented state %d\n", ss);
474         return E_NOTIMPL;
475     }
476 
477     change_state(This, ss);
478     return S_OK;
479 }
480 
481 static HRESULT WINAPI VBScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
482 {
483     VBScript *This = impl_from_IActiveScript(iface);
484 
485     TRACE("(%p)->(%p)\n", This, pssState);
486 
487     if(!pssState)
488         return E_POINTER;
489 
490     if(This->thread_id && This->thread_id != GetCurrentThreadId())
491         return E_UNEXPECTED;
492 
493     *pssState = This->state;
494     return S_OK;
495 }
496 
497 static HRESULT WINAPI VBScript_Close(IActiveScript *iface)
498 {
499     VBScript *This = impl_from_IActiveScript(iface);
500 
501     TRACE("(%p)->()\n", This);
502 
503     if(This->thread_id && This->thread_id != GetCurrentThreadId())
504         return E_UNEXPECTED;
505 
506     decrease_state(This, SCRIPTSTATE_CLOSED);
507     return S_OK;
508 }
509 
510 static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstrName, DWORD dwFlags)
511 {
512     VBScript *This = impl_from_IActiveScript(iface);
513     named_item_t *item;
514     IDispatch *disp = NULL;
515     HRESULT hres;
516 
517     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags);
518 
519     if(This->thread_id != GetCurrentThreadId() || !This->ctx->site)
520         return E_UNEXPECTED;
521 
522     if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) {
523         IUnknown *unk;
524 
525         hres = IActiveScriptSite_GetItemInfo(This->ctx->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL);
526         if(FAILED(hres)) {
527             WARN("GetItemInfo failed: %08x\n", hres);
528             return hres;
529         }
530 
531         hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
532         IUnknown_Release(unk);
533         if(FAILED(hres)) {
534             WARN("object does not implement IDispatch\n");
535             return hres;
536         }
537 
538         if(This->ctx->host_global)
539             IDispatch_Release(This->ctx->host_global);
540         IDispatch_AddRef(disp);
541         This->ctx->host_global = disp;
542     }
543 
544     item = heap_alloc(sizeof(*item));
545     if(!item) {
546         if(disp)
547             IDispatch_Release(disp);
548         return E_OUTOFMEMORY;
549     }
550 
551     item->disp = disp;
552     item->flags = dwFlags;
553     item->name = heap_strdupW(pstrName);
554     if(!item->name) {
555         if(disp)
556             IDispatch_Release(disp);
557         heap_free(item);
558         return E_OUTOFMEMORY;
559     }
560 
561     list_add_tail(&This->ctx->named_items, &item->entry);
562     return S_OK;
563 }
564 
565 static HRESULT WINAPI VBScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
566         DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
567 {
568     VBScript *This = impl_from_IActiveScript(iface);
569     FIXME("(%p)->()\n", This);
570     return E_NOTIMPL;
571 }
572 
573 static HRESULT WINAPI VBScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp)
574 {
575     VBScript *This = impl_from_IActiveScript(iface);
576 
577     TRACE("(%p)->(%p)\n", This, ppdisp);
578 
579     if(!ppdisp)
580         return E_POINTER;
581 
582     if(This->thread_id != GetCurrentThreadId() || !This->ctx->script_obj) {
583         *ppdisp = NULL;
584         return E_UNEXPECTED;
585     }
586 
587     *ppdisp = (IDispatch*)&This->ctx->script_obj->IDispatchEx_iface;
588     IDispatch_AddRef(*ppdisp);
589     return S_OK;
590 }
591 
592 static HRESULT WINAPI VBScript_GetCurrentScriptThreadID(IActiveScript *iface,
593                                                        SCRIPTTHREADID *pstridThread)
594 {
595     VBScript *This = impl_from_IActiveScript(iface);
596     FIXME("(%p)->()\n", This);
597     return E_NOTIMPL;
598 }
599 
600 static HRESULT WINAPI VBScript_GetScriptThreadID(IActiveScript *iface,
601                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
602 {
603     VBScript *This = impl_from_IActiveScript(iface);
604     FIXME("(%p)->()\n", This);
605     return E_NOTIMPL;
606 }
607 
608 static HRESULT WINAPI VBScript_GetScriptThreadState(IActiveScript *iface,
609         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
610 {
611     VBScript *This = impl_from_IActiveScript(iface);
612     FIXME("(%p)->()\n", This);
613     return E_NOTIMPL;
614 }
615 
616 static HRESULT WINAPI VBScript_InterruptScriptThread(IActiveScript *iface,
617         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
618 {
619     VBScript *This = impl_from_IActiveScript(iface);
620     FIXME("(%p)->()\n", This);
621     return E_NOTIMPL;
622 }
623 
624 static HRESULT WINAPI VBScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
625 {
626     VBScript *This = impl_from_IActiveScript(iface);
627     FIXME("(%p)->()\n", This);
628     return E_NOTIMPL;
629 }
630 
631 static const IActiveScriptVtbl VBScriptVtbl = {
632     VBScript_QueryInterface,
633     VBScript_AddRef,
634     VBScript_Release,
635     VBScript_SetScriptSite,
636     VBScript_GetScriptSite,
637     VBScript_SetScriptState,
638     VBScript_GetScriptState,
639     VBScript_Close,
640     VBScript_AddNamedItem,
641     VBScript_AddTypeLib,
642     VBScript_GetScriptDispatch,
643     VBScript_GetCurrentScriptThreadID,
644     VBScript_GetScriptThreadID,
645     VBScript_GetScriptThreadState,
646     VBScript_InterruptScriptThread,
647     VBScript_Clone
648 };
649 
650 static inline VBScript *impl_from_IActiveScriptDebug(IActiveScriptDebug *iface)
651 {
652     return CONTAINING_RECORD(iface, VBScript, IActiveScriptDebug_iface);
653 }
654 
655 static HRESULT WINAPI VBScriptDebug_QueryInterface(IActiveScriptDebug *iface, REFIID riid, void **ppv)
656 {
657     VBScript *This = impl_from_IActiveScriptDebug(iface);
658     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
659 }
660 
661 static ULONG WINAPI VBScriptDebug_AddRef(IActiveScriptDebug *iface)
662 {
663     VBScript *This = impl_from_IActiveScriptDebug(iface);
664     return IActiveScript_AddRef(&This->IActiveScript_iface);
665 }
666 
667 static ULONG WINAPI VBScriptDebug_Release(IActiveScriptDebug *iface)
668 {
669     VBScript *This = impl_from_IActiveScriptDebug(iface);
670     return IActiveScript_Release(&This->IActiveScript_iface);
671 }
672 
673 static HRESULT WINAPI VBScriptDebug_GetScriptTextAttributes(IActiveScriptDebug *iface,
674         LPCOLESTR code, ULONG len, LPCOLESTR delimiter, DWORD flags, SOURCE_TEXT_ATTR *attr)
675 {
676     VBScript *This = impl_from_IActiveScriptDebug(iface);
677     FIXME("(%p)->(%s %u %s %#x %p)\n", This, debugstr_w(code), len,
678           debugstr_w(delimiter), flags, attr);
679     return E_NOTIMPL;
680 }
681 
682 static HRESULT WINAPI VBScriptDebug_GetScriptletTextAttributes(IActiveScriptDebug *iface,
683         LPCOLESTR code, ULONG len, LPCOLESTR delimiter, DWORD flags, SOURCE_TEXT_ATTR *attr)
684 {
685     VBScript *This = impl_from_IActiveScriptDebug(iface);
686     FIXME("(%p)->(%s %u %s %#x %p)\n", This, debugstr_w(code), len,
687           debugstr_w(delimiter), flags, attr);
688     return E_NOTIMPL;
689 }
690 
691 static HRESULT WINAPI VBScriptDebug_EnumCodeContextsOfPosition(IActiveScriptDebug *iface,
692         CTXARG_T source, ULONG offset, ULONG len, IEnumDebugCodeContexts **ret)
693 {
694     VBScript *This = impl_from_IActiveScriptDebug(iface);
695     FIXME("(%p)->(%s %u %u %p)\n", This, wine_dbgstr_longlong(source), offset, len, ret);
696     return E_NOTIMPL;
697 }
698 
699 static const IActiveScriptDebugVtbl VBScriptDebugVtbl = {
700     VBScriptDebug_QueryInterface,
701     VBScriptDebug_AddRef,
702     VBScriptDebug_Release,
703     VBScriptDebug_GetScriptTextAttributes,
704     VBScriptDebug_GetScriptletTextAttributes,
705     VBScriptDebug_EnumCodeContextsOfPosition,
706 };
707 
708 static inline VBScript *impl_from_IActiveScriptParse(IActiveScriptParse *iface)
709 {
710     return CONTAINING_RECORD(iface, VBScript, IActiveScriptParse_iface);
711 }
712 
713 static HRESULT WINAPI VBScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
714 {
715     VBScript *This = impl_from_IActiveScriptParse(iface);
716     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
717 }
718 
719 static ULONG WINAPI VBScriptParse_AddRef(IActiveScriptParse *iface)
720 {
721     VBScript *This = impl_from_IActiveScriptParse(iface);
722     return IActiveScript_AddRef(&This->IActiveScript_iface);
723 }
724 
725 static ULONG WINAPI VBScriptParse_Release(IActiveScriptParse *iface)
726 {
727     VBScript *This = impl_from_IActiveScriptParse(iface);
728     return IActiveScript_Release(&This->IActiveScript_iface);
729 }
730 
731 static HRESULT WINAPI VBScriptParse_InitNew(IActiveScriptParse *iface)
732 {
733     VBScript *This = impl_from_IActiveScriptParse(iface);
734 
735     TRACE("(%p)\n", This);
736 
737     if(This->is_initialized)
738         return E_UNEXPECTED;
739     This->is_initialized = TRUE;
740 
741     if(This->ctx->site)
742         change_state(This, SCRIPTSTATE_INITIALIZED);
743     return S_OK;
744 }
745 
746 static HRESULT WINAPI VBScriptParse_AddScriptlet(IActiveScriptParse *iface,
747         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
748         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
749         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
750         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
751 {
752     VBScript *This = impl_from_IActiveScriptParse(iface);
753     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
754           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
755           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
756           ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo);
757     return E_NOTIMPL;
758 }
759 
760 static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface,
761         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
762         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
763         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
764 {
765     VBScript *This = impl_from_IActiveScriptParse(iface);
766     IDispatch *context = NULL;
767     vbscode_t *code;
768     HRESULT hres;
769 
770     TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
771           debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
772           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
773 
774     if(This->thread_id != GetCurrentThreadId() || This->state == SCRIPTSTATE_CLOSED)
775         return E_UNEXPECTED;
776 
777     if(pstrItemName) {
778         context = lookup_named_item(This->ctx, pstrItemName, 0);
779         if(!context) {
780             WARN("Inknown context %s\n", debugstr_w(pstrItemName));
781             return E_INVALIDARG;
782         }
783     }
784 
785     hres = compile_script(This->ctx, pstrCode, pstrDelimiter, dwFlags, &code);
786     if(FAILED(hres))
787         return hres;
788 
789     if(context)
790         IDispatch_AddRef(code->context = context);
791 
792     if(!(dwFlags & SCRIPTTEXT_ISEXPRESSION) && !is_started(This)) {
793         code->pending_exec = TRUE;
794         return S_OK;
795     }
796 
797     return exec_global_code(This->ctx, code, pvarResult);
798 }
799 
800 static const IActiveScriptParseVtbl VBScriptParseVtbl = {
801     VBScriptParse_QueryInterface,
802     VBScriptParse_AddRef,
803     VBScriptParse_Release,
804     VBScriptParse_InitNew,
805     VBScriptParse_AddScriptlet,
806     VBScriptParse_ParseScriptText
807 };
808 
809 static inline VBScript *impl_from_IActiveScriptParseProcedure2(IActiveScriptParseProcedure2 *iface)
810 {
811     return CONTAINING_RECORD(iface, VBScript, IActiveScriptParseProcedure2_iface);
812 }
813 
814 static HRESULT WINAPI VBScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv)
815 {
816     VBScript *This = impl_from_IActiveScriptParseProcedure2(iface);
817     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
818 }
819 
820 static ULONG WINAPI VBScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface)
821 {
822     VBScript *This = impl_from_IActiveScriptParseProcedure2(iface);
823     return IActiveScript_AddRef(&This->IActiveScript_iface);
824 }
825 
826 static ULONG WINAPI VBScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface)
827 {
828     VBScript *This = impl_from_IActiveScriptParseProcedure2(iface);
829     return IActiveScript_Release(&This->IActiveScript_iface);
830 }
831 
832 static HRESULT WINAPI VBScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface,
833         LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName,
834         LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter,
835         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
836 {
837     VBScript *This = impl_from_IActiveScriptParseProcedure2(iface);
838     class_desc_t *desc;
839     vbdisp_t *vbdisp;
840     HRESULT hres;
841 
842     TRACE("(%p)->(%s %s %s %s %p %s %s %u %x %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams),
843           debugstr_w(pstrProcedureName), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
844           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLineNumber, dwFlags, ppdisp);
845 
846     if(This->thread_id != GetCurrentThreadId() || This->state == SCRIPTSTATE_CLOSED)
847         return E_UNEXPECTED;
848 
849     hres = compile_procedure(This->ctx, pstrCode, pstrDelimiter, dwFlags, &desc);
850     if(FAILED(hres))
851         return hres;
852 
853     hres = create_vbdisp(desc, &vbdisp);
854     if(FAILED(hres))
855         return hres;
856 
857     *ppdisp = (IDispatch*)&vbdisp->IDispatchEx_iface;
858     return S_OK;
859 }
860 
861 static const IActiveScriptParseProcedure2Vtbl VBScriptParseProcedureVtbl = {
862     VBScriptParseProcedure_QueryInterface,
863     VBScriptParseProcedure_AddRef,
864     VBScriptParseProcedure_Release,
865     VBScriptParseProcedure_ParseProcedureText,
866 };
867 
868 static inline VBScript *impl_from_IObjectSafety(IObjectSafety *iface)
869 {
870     return CONTAINING_RECORD(iface, VBScript, IObjectSafety_iface);
871 }
872 
873 static HRESULT WINAPI VBScriptSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
874 {
875     VBScript *This = impl_from_IObjectSafety(iface);
876     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
877 }
878 
879 static ULONG WINAPI VBScriptSafety_AddRef(IObjectSafety *iface)
880 {
881     VBScript *This = impl_from_IObjectSafety(iface);
882     return IActiveScript_AddRef(&This->IActiveScript_iface);
883 }
884 
885 static ULONG WINAPI VBScriptSafety_Release(IObjectSafety *iface)
886 {
887     VBScript *This = impl_from_IObjectSafety(iface);
888     return IActiveScript_Release(&This->IActiveScript_iface);
889 }
890 
891 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
892 
893 static HRESULT WINAPI VBScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
894         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
895 {
896     VBScript *This = impl_from_IObjectSafety(iface);
897 
898     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
899 
900     if(!pdwSupportedOptions || !pdwEnabledOptions)
901         return E_POINTER;
902 
903     *pdwSupportedOptions = SUPPORTED_OPTIONS;
904     *pdwEnabledOptions = This->ctx->safeopt;
905     return S_OK;
906 }
907 
908 static HRESULT WINAPI VBScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
909         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
910 {
911     VBScript *This = impl_from_IObjectSafety(iface);
912 
913     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
914 
915     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
916         return E_FAIL;
917 
918     This->ctx->safeopt = (dwEnabledOptions & dwOptionSetMask) | (This->ctx->safeopt & ~dwOptionSetMask) | INTERFACE_USES_DISPEX;
919     return S_OK;
920 }
921 
922 static const IObjectSafetyVtbl VBScriptSafetyVtbl = {
923     VBScriptSafety_QueryInterface,
924     VBScriptSafety_AddRef,
925     VBScriptSafety_Release,
926     VBScriptSafety_GetInterfaceSafetyOptions,
927     VBScriptSafety_SetInterfaceSafetyOptions
928 };
929 
930 HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
931 {
932     script_ctx_t *ctx;
933     VBScript *ret;
934     HRESULT hres;
935 
936     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
937 
938     ret = heap_alloc_zero(sizeof(*ret));
939     if(!ret)
940         return E_OUTOFMEMORY;
941 
942     ret->IActiveScript_iface.lpVtbl = &VBScriptVtbl;
943     ret->IActiveScriptDebug_iface.lpVtbl = &VBScriptDebugVtbl;
944     ret->IActiveScriptParse_iface.lpVtbl = &VBScriptParseVtbl;
945     ret->IActiveScriptParseProcedure2_iface.lpVtbl = &VBScriptParseProcedureVtbl;
946     ret->IObjectSafety_iface.lpVtbl = &VBScriptSafetyVtbl;
947 
948     ret->ref = 1;
949     ret->state = SCRIPTSTATE_UNINITIALIZED;
950 
951     ctx = ret->ctx = heap_alloc_zero(sizeof(*ctx));
952     if(!ctx) {
953         heap_free(ret);
954         return E_OUTOFMEMORY;
955     }
956 
957     ctx->safeopt = INTERFACE_USES_DISPEX;
958     heap_pool_init(&ctx->heap);
959     list_init(&ctx->objects);
960     list_init(&ctx->code_list);
961     list_init(&ctx->named_items);
962 
963     hres = init_global(ctx);
964     if(FAILED(hres)) {
965         IActiveScript_Release(&ret->IActiveScript_iface);
966         return hres;
967     }
968 
969     hres = IActiveScript_QueryInterface(&ret->IActiveScript_iface, riid, ppv);
970     IActiveScript_Release(&ret->IActiveScript_iface);
971     return hres;
972 }
973 
974 typedef struct {
975     IServiceProvider IServiceProvider_iface;
976 
977     LONG ref;
978 
979     IServiceProvider *sp;
980 } AXSite;
981 
982 static inline AXSite *impl_from_IServiceProvider(IServiceProvider *iface)
983 {
984     return CONTAINING_RECORD(iface, AXSite, IServiceProvider_iface);
985 }
986 
987 static HRESULT WINAPI AXSite_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
988 {
989     AXSite *This = impl_from_IServiceProvider(iface);
990 
991     if(IsEqualGUID(&IID_IUnknown, riid)) {
992         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
993         *ppv = &This->IServiceProvider_iface;
994     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
995         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
996         *ppv = &This->IServiceProvider_iface;
997     }else {
998         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
999         *ppv = NULL;
1000         return E_NOINTERFACE;
1001     }
1002 
1003     IUnknown_AddRef((IUnknown*)*ppv);
1004     return S_OK;
1005 }
1006 
1007 static ULONG WINAPI AXSite_AddRef(IServiceProvider *iface)
1008 {
1009     AXSite *This = impl_from_IServiceProvider(iface);
1010     LONG ref = InterlockedIncrement(&This->ref);
1011 
1012     TRACE("(%p) ref=%d\n", This, ref);
1013 
1014     return ref;
1015 }
1016 
1017 static ULONG WINAPI AXSite_Release(IServiceProvider *iface)
1018 {
1019     AXSite *This = impl_from_IServiceProvider(iface);
1020     LONG ref = InterlockedDecrement(&This->ref);
1021 
1022     TRACE("(%p) ref=%d\n", This, ref);
1023 
1024     if(!ref)
1025         heap_free(This);
1026 
1027     return ref;
1028 }
1029 
1030 static HRESULT WINAPI AXSite_QueryService(IServiceProvider *iface,
1031         REFGUID guidService, REFIID riid, void **ppv)
1032 {
1033     AXSite *This = impl_from_IServiceProvider(iface);
1034 
1035     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1036 
1037     return IServiceProvider_QueryService(This->sp, guidService, riid, ppv);
1038 }
1039 
1040 static IServiceProviderVtbl AXSiteVtbl = {
1041     AXSite_QueryInterface,
1042     AXSite_AddRef,
1043     AXSite_Release,
1044     AXSite_QueryService
1045 };
1046 
1047 IUnknown *create_ax_site(script_ctx_t *ctx)
1048 {
1049     IServiceProvider *sp;
1050     AXSite *ret;
1051     HRESULT hres;
1052 
1053     hres = IActiveScriptSite_QueryInterface(ctx->site, &IID_IServiceProvider, (void**)&sp);
1054     if(FAILED(hres)) {
1055         ERR("Could not get IServiceProvider iface: %08x\n", hres);
1056         return NULL;
1057     }
1058 
1059     ret = heap_alloc(sizeof(*ret));
1060     if(!ret) {
1061         IServiceProvider_Release(sp);
1062         return NULL;
1063     }
1064 
1065     ret->IServiceProvider_iface.lpVtbl = &AXSiteVtbl;
1066     ret->ref = 1;
1067     ret->sp = sp;
1068 
1069     return (IUnknown*)&ret->IServiceProvider_iface;
1070 }
1071