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