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