user32/tests: Fix some window test failures on various Windows platforms.
[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 "jscript.h"
20 #include "engine.h"
21 #include "objsafe.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
26
27 #ifdef _WIN64
28
29 #define CTXARG_T DWORDLONG
30 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
31
32 #else
33
34 #define CTXARG_T DWORD
35 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
36
37 #endif
38
39 typedef struct {
40     const IActiveScriptVtbl                 *lpIActiveScriptVtbl;
41     const IActiveScriptParseVtbl            *lpIActiveScriptParseVtbl;
42     const IActiveScriptParseProcedure2Vtbl  *lpIActiveScriptParseProcedure2Vtbl;
43     const IActiveScriptPropertyVtbl         *lpIActiveScriptPropertyVtbl;
44     const IObjectSafetyVtbl                 *lpIObjectSafetyVtbl;
45
46     LONG ref;
47
48     DWORD safeopt;
49     script_ctx_t *ctx;
50     LONG thread_id;
51     LCID lcid;
52
53     IActiveScriptSite *site;
54
55     parser_ctx_t *queue_head;
56     parser_ctx_t *queue_tail;
57 } JScript;
58
59 #define ACTSCRIPT(x)    ((IActiveScript*) &(x)->lpIActiveScriptVtbl)
60 #define ASPARSE(x)      (&(x)->lpIActiveScriptParseVtbl)
61 #define ASPARSEPROC(x)  (&(x)->lpIActiveScriptParseProcedure2Vtbl)
62 #define ACTSCPPROP(x)   (&(x)->lpIActiveScriptPropertyVtbl)
63 #define OBJSAFETY(x)    (&(x)->lpIObjectSafetyVtbl)
64
65 void script_release(script_ctx_t *ctx)
66 {
67     if(--ctx->ref)
68         return;
69
70     jsheap_free(&ctx->tmp_heap);
71     heap_free(ctx);
72 }
73
74 static void change_state(JScript *This, SCRIPTSTATE state)
75 {
76     if(This->ctx->state == state)
77         return;
78
79     This->ctx->state = state;
80     IActiveScriptSite_OnStateChange(This->site, state);
81 }
82
83 static inline BOOL is_started(script_ctx_t *ctx)
84 {
85     return ctx->state == SCRIPTSTATE_STARTED
86         || ctx->state == SCRIPTSTATE_CONNECTED
87         || ctx->state == SCRIPTSTATE_DISCONNECTED;
88 }
89
90 static HRESULT exec_global_code(JScript *This, parser_ctx_t *parser_ctx)
91 {
92     exec_ctx_t *exec_ctx;
93     jsexcept_t jsexcept;
94     VARIANT var;
95     HRESULT hres;
96
97     hres = create_exec_ctx((IDispatch*)_IDispatchEx_(This->ctx->script_disp), This->ctx->script_disp, NULL, &exec_ctx);
98     if(FAILED(hres))
99         return hres;
100
101     IActiveScriptSite_OnEnterScript(This->site);
102
103     memset(&jsexcept, 0, sizeof(jsexcept));
104     hres = exec_source(exec_ctx, parser_ctx, parser_ctx->source, &jsexcept, &var);
105     VariantClear(&jsexcept.var);
106     exec_release(exec_ctx);
107     if(SUCCEEDED(hres))
108         VariantClear(&var);
109
110     IActiveScriptSite_OnLeaveScript(This->site);
111
112     return hres;
113 }
114
115 static void clear_script_queue(JScript *This)
116 {
117     parser_ctx_t *iter, *iter2;
118
119     if(!This->queue_head)
120         return;
121
122     iter = This->queue_head;
123     while(iter) {
124         iter2 = iter->next;
125         iter->next = NULL;
126         parser_release(iter);
127         iter = iter2;
128     }
129
130     This->queue_head = This->queue_tail = NULL;
131 }
132
133 static void exec_queued_code(JScript *This)
134 {
135     parser_ctx_t *iter;
136
137     for(iter = This->queue_head; iter; iter = iter->next)
138         exec_global_code(This, iter);
139
140     clear_script_queue(This);
141 }
142
143 static HRESULT set_ctx_site(JScript *This)
144 {
145     HRESULT hres;
146
147     This->ctx->lcid = This->lcid;
148
149     if(!This->ctx->script_disp) {
150         hres = create_dispex(This->ctx, NULL, NULL, &This->ctx->script_disp);
151         if(FAILED(hres))
152             return hres;
153     }
154
155     hres = init_global(This->ctx);
156     if(FAILED(hres))
157         return hres;
158
159     IActiveScriptSite_AddRef(This->site);
160     This->ctx->site = This->site;
161
162     change_state(This, SCRIPTSTATE_INITIALIZED);
163     return S_OK;
164 }
165
166 #define ACTSCRIPT_THIS(iface) DEFINE_THIS(JScript, IActiveScript, iface)
167
168 static HRESULT WINAPI JScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
169 {
170     JScript *This = ACTSCRIPT_THIS(iface);
171
172     *ppv = NULL;
173
174     if(IsEqualGUID(riid, &IID_IUnknown)) {
175         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
176         *ppv = ACTSCRIPT(This);
177     }else if(IsEqualGUID(riid, &IID_IActiveScript)) {
178         TRACE("(%p)->(IID_IActiveScript %p)\n", This, ppv);
179         *ppv = ACTSCRIPT(This);
180     }else if(IsEqualGUID(riid, &IID_IActiveScriptParse)) {
181         TRACE("(%p)->(IID_IActiveScriptParse %p)\n", This, ppv);
182         *ppv = ASPARSE(This);
183     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure)) {
184         TRACE("(%p)->(IID_IActiveScriptParseProcedure %p)\n", This, ppv);
185         *ppv = ASPARSEPROC(This);
186     }else if(IsEqualGUID(riid, &IID_IActiveScriptParseProcedure2)) {
187         TRACE("(%p)->(IID_IActiveScriptParseProcedure2 %p)\n", This, ppv);
188         *ppv = ASPARSEPROC(This);
189     }else if(IsEqualGUID(riid, &IID_IActiveScriptProperty)) {
190         TRACE("(%p)->(IID_IActiveScriptProperty %p)\n", This, ppv);
191         *ppv = ACTSCPPROP(This);
192     }else if(IsEqualGUID(riid, &IID_IObjectSafety)) {
193         TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv);
194         *ppv = OBJSAFETY(This);
195     }
196
197     if(*ppv) {
198         IUnknown_AddRef((IUnknown*)*ppv);
199         return S_OK;
200     }
201
202     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
203     return E_NOINTERFACE;
204 }
205
206 static ULONG WINAPI JScript_AddRef(IActiveScript *iface)
207 {
208     JScript *This = ACTSCRIPT_THIS(iface);
209     LONG ref = InterlockedIncrement(&This->ref);
210
211     TRACE("(%p) ref=%d\n", This, ref);
212
213     return ref;
214 }
215
216 static ULONG WINAPI JScript_Release(IActiveScript *iface)
217 {
218     JScript *This = ACTSCRIPT_THIS(iface);
219     LONG ref = InterlockedDecrement(&This->ref);
220
221     TRACE("(%p) ref=%d\n", iface, ref);
222
223     if(!ref) {
224         if(This->ctx && This->ctx->state != SCRIPTSTATE_CLOSED)
225             IActiveScript_Close(ACTSCRIPT(This));
226         if(This->ctx)
227             script_release(This->ctx);
228         heap_free(This);
229         unlock_module();
230     }
231
232     return ref;
233 }
234
235 static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface,
236                                             IActiveScriptSite *pass)
237 {
238     JScript *This = ACTSCRIPT_THIS(iface);
239     LCID lcid;
240     HRESULT hres;
241
242     TRACE("(%p)->(%p)\n", This, pass);
243
244     if(!pass)
245         return E_POINTER;
246
247     if(This->site)
248         return E_UNEXPECTED;
249
250     if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0))
251         return E_UNEXPECTED;
252
253     This->site = pass;
254     IActiveScriptSite_AddRef(This->site);
255
256     hres = IActiveScriptSite_GetLCID(This->site, &lcid);
257     if(hres == S_OK)
258         This->lcid = lcid;
259
260     return This->ctx ? set_ctx_site(This) : S_OK;
261 }
262
263 static HRESULT WINAPI JScript_GetScriptSite(IActiveScript *iface, REFIID riid,
264                                             void **ppvObject)
265 {
266     JScript *This = ACTSCRIPT_THIS(iface);
267     FIXME("(%p)->()\n", This);
268     return E_NOTIMPL;
269 }
270
271 static HRESULT WINAPI JScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
272 {
273     JScript *This = ACTSCRIPT_THIS(iface);
274
275     TRACE("(%p)->(%d)\n", This, ss);
276
277     if(!This->ctx || GetCurrentThreadId() != This->thread_id)
278         return E_UNEXPECTED;
279
280     switch(ss) {
281     case SCRIPTSTATE_STARTED:
282     case SCRIPTSTATE_CONNECTED: /* FIXME */
283         if(This->ctx->state == SCRIPTSTATE_CLOSED)
284             return E_UNEXPECTED;
285
286         exec_queued_code(This);
287         break;
288     default:
289         FIXME("unimplemented state %d\n", ss);
290         return E_NOTIMPL;
291     }
292
293     change_state(This, ss);
294     return S_OK;
295 }
296
297 static HRESULT WINAPI JScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
298 {
299     JScript *This = ACTSCRIPT_THIS(iface);
300
301     TRACE("(%p)->(%p)\n", This, pssState);
302
303     if(!pssState)
304         return E_POINTER;
305
306     if(!This->thread_id) {
307         *pssState = SCRIPTSTATE_UNINITIALIZED;
308         return S_OK;
309     }
310
311     if(This->thread_id != GetCurrentThreadId())
312         return E_UNEXPECTED;
313
314     *pssState = This->ctx ? This->ctx->state : SCRIPTSTATE_UNINITIALIZED;
315     return S_OK;
316 }
317
318 static HRESULT WINAPI JScript_Close(IActiveScript *iface)
319 {
320     JScript *This = ACTSCRIPT_THIS(iface);
321
322     TRACE("(%p)->()\n", This);
323
324     if(This->thread_id != GetCurrentThreadId())
325         return E_UNEXPECTED;
326
327     if(This->ctx) {
328         if(This->ctx->state == SCRIPTSTATE_CONNECTED)
329             change_state(This, SCRIPTSTATE_DISCONNECTED);
330
331         clear_script_queue(This);
332
333         if(This->ctx->state == SCRIPTSTATE_DISCONNECTED)
334             change_state(This, SCRIPTSTATE_INITIALIZED);
335
336         if(This->ctx->named_items) {
337             named_item_t *iter, *iter2;
338
339             iter = This->ctx->named_items;
340             while(iter) {
341                 iter2 = iter->next;
342
343                 if(iter->disp)
344                     IDispatch_Release(iter->disp);
345                 heap_free(iter->name);
346                 heap_free(iter);
347                 iter = iter2;
348             }
349
350             This->ctx->named_items = NULL;
351         }
352
353         if(This->ctx->site) {
354             IActiveScriptSite_Release(This->ctx->site);
355             This->ctx->site = NULL;
356         }
357
358         if (This->site)
359             change_state(This, SCRIPTSTATE_CLOSED);
360
361         if(This->ctx->script_disp) {
362             IDispatchEx_Release(_IDispatchEx_(This->ctx->script_disp));
363             This->ctx->script_disp = NULL;
364         }
365
366         if(This->ctx->global) {
367             IDispatchEx_Release(_IDispatchEx_(This->ctx->global));
368             This->ctx->global = NULL;
369         }
370     }
371
372     if(This->site) {
373         IActiveScriptSite_Release(This->site);
374         This->site = NULL;
375     }
376
377     return S_OK;
378 }
379
380 static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface,
381                                            LPCOLESTR pstrName, DWORD dwFlags)
382 {
383     JScript *This = ACTSCRIPT_THIS(iface);
384     named_item_t *item;
385     IDispatch *disp = NULL;
386     HRESULT hres;
387
388     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags);
389
390     if(This->thread_id != GetCurrentThreadId() || !This->ctx || This->ctx->state == SCRIPTSTATE_CLOSED)
391         return E_UNEXPECTED;
392
393     if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) {
394         IUnknown *unk;
395
396         hres = IActiveScriptSite_GetItemInfo(This->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL);
397         if(FAILED(hres)) {
398             WARN("GetItemInfo failed: %08x\n", hres);
399             return hres;
400         }
401
402         hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
403         IUnknown_Release(unk);
404         if(FAILED(hres)) {
405             WARN("object does not implement IDispatch\n");
406             return hres;
407         }
408     }
409
410     item = heap_alloc(sizeof(*item));
411     if(!item) {
412         if(disp)
413             IDispatch_Release(disp);
414         return E_OUTOFMEMORY;
415     }
416
417     item->disp = disp;
418     item->flags = dwFlags;
419     item->name = heap_strdupW(pstrName);
420     if(!item->name) {
421         IDispatch_Release(disp);
422         heap_free(item);
423         return E_OUTOFMEMORY;
424     }
425
426     item->next = This->ctx->named_items;
427     This->ctx->named_items = item;
428
429     return S_OK;
430 }
431
432 static HRESULT WINAPI JScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
433                                          DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
434 {
435     JScript *This = ACTSCRIPT_THIS(iface);
436     FIXME("(%p)->()\n", This);
437     return E_NOTIMPL;
438 }
439
440 static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
441                                                 IDispatch **ppdisp)
442 {
443     JScript *This = ACTSCRIPT_THIS(iface);
444
445     TRACE("(%p)->(%p)\n", This, ppdisp);
446
447     if(!ppdisp)
448         return E_POINTER;
449
450     if(This->thread_id != GetCurrentThreadId() || !This->ctx->script_disp) {
451         *ppdisp = NULL;
452         return E_UNEXPECTED;
453     }
454
455     *ppdisp = (IDispatch*)_IDispatchEx_(This->ctx->script_disp);
456     IDispatch_AddRef(*ppdisp);
457     return S_OK;
458 }
459
460 static HRESULT WINAPI JScript_GetCurrentScriptThreadID(IActiveScript *iface,
461                                                        SCRIPTTHREADID *pstridThread)
462 {
463     JScript *This = ACTSCRIPT_THIS(iface);
464     FIXME("(%p)->()\n", This);
465     return E_NOTIMPL;
466 }
467
468 static HRESULT WINAPI JScript_GetScriptThreadID(IActiveScript *iface,
469                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
470 {
471     JScript *This = ACTSCRIPT_THIS(iface);
472     FIXME("(%p)->()\n", This);
473     return E_NOTIMPL;
474 }
475
476 static HRESULT WINAPI JScript_GetScriptThreadState(IActiveScript *iface,
477         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
478 {
479     JScript *This = ACTSCRIPT_THIS(iface);
480     FIXME("(%p)->()\n", This);
481     return E_NOTIMPL;
482 }
483
484 static HRESULT WINAPI JScript_InterruptScriptThread(IActiveScript *iface,
485         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
486 {
487     JScript *This = ACTSCRIPT_THIS(iface);
488     FIXME("(%p)->()\n", This);
489     return E_NOTIMPL;
490 }
491
492 static HRESULT WINAPI JScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
493 {
494     JScript *This = ACTSCRIPT_THIS(iface);
495     FIXME("(%p)->()\n", This);
496     return E_NOTIMPL;
497 }
498
499 #undef ACTSCRIPT_THIS
500
501 static const IActiveScriptVtbl JScriptVtbl = {
502     JScript_QueryInterface,
503     JScript_AddRef,
504     JScript_Release,
505     JScript_SetScriptSite,
506     JScript_GetScriptSite,
507     JScript_SetScriptState,
508     JScript_GetScriptState,
509     JScript_Close,
510     JScript_AddNamedItem,
511     JScript_AddTypeLib,
512     JScript_GetScriptDispatch,
513     JScript_GetCurrentScriptThreadID,
514     JScript_GetScriptThreadID,
515     JScript_GetScriptThreadState,
516     JScript_InterruptScriptThread,
517     JScript_Clone
518 };
519
520 #define ASPARSE_THIS(iface) DEFINE_THIS(JScript, IActiveScriptParse, iface)
521
522 static HRESULT WINAPI JScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
523 {
524     JScript *This = ASPARSE_THIS(iface);
525     return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
526 }
527
528 static ULONG WINAPI JScriptParse_AddRef(IActiveScriptParse *iface)
529 {
530     JScript *This = ASPARSE_THIS(iface);
531     return IActiveScript_AddRef(ACTSCRIPT(This));
532 }
533
534 static ULONG WINAPI JScriptParse_Release(IActiveScriptParse *iface)
535 {
536     JScript *This = ASPARSE_THIS(iface);
537     return IActiveScript_Release(ACTSCRIPT(This));
538 }
539
540 static HRESULT WINAPI JScriptParse_InitNew(IActiveScriptParse *iface)
541 {
542     JScript *This = ASPARSE_THIS(iface);
543     script_ctx_t *ctx;
544
545     TRACE("(%p)\n", This);
546
547     if(This->ctx)
548         return E_UNEXPECTED;
549
550     ctx = heap_alloc_zero(sizeof(script_ctx_t));
551     if(!ctx)
552         return E_OUTOFMEMORY;
553
554     ctx->ref = 1;
555     ctx->state = SCRIPTSTATE_UNINITIALIZED;
556     jsheap_init(&ctx->tmp_heap);
557
558     ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL);
559     if(ctx) {
560         script_release(ctx);
561         return E_UNEXPECTED;
562     }
563
564     return This->site ? set_ctx_site(This) : S_OK;
565 }
566
567 static HRESULT WINAPI JScriptParse_AddScriptlet(IActiveScriptParse *iface,
568         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
569         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
570         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
571         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
572 {
573     JScript *This = ASPARSE_THIS(iface);
574     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
575           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
576           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
577           ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo);
578     return E_NOTIMPL;
579 }
580
581 static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface,
582         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
583         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
584         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
585 {
586     JScript *This = ASPARSE_THIS(iface);
587     parser_ctx_t *parser_ctx;
588     HRESULT hres;
589
590     TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
591           debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
592           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
593
594     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
595         return E_UNEXPECTED;
596
597     hres = script_parse(This->ctx, pstrCode, &parser_ctx);
598     if(FAILED(hres))
599         return hres;
600
601     if(!is_started(This->ctx)) {
602         if(This->queue_tail)
603             This->queue_tail = This->queue_tail->next = parser_ctx;
604         else
605             This->queue_head = This->queue_tail = parser_ctx;
606         return S_OK;
607     }
608
609     hres = exec_global_code(This, parser_ctx);
610     parser_release(parser_ctx);
611
612     return hres;
613 }
614
615 #undef ASPARSE_THIS
616
617 static const IActiveScriptParseVtbl JScriptParseVtbl = {
618     JScriptParse_QueryInterface,
619     JScriptParse_AddRef,
620     JScriptParse_Release,
621     JScriptParse_InitNew,
622     JScriptParse_AddScriptlet,
623     JScriptParse_ParseScriptText
624 };
625
626 #define ASPARSEPROC_THIS(iface) DEFINE_THIS(JScript, IActiveScriptParseProcedure2, iface)
627
628 static HRESULT WINAPI JScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv)
629 {
630     JScript *This = ASPARSEPROC_THIS(iface);
631     return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
632 }
633
634 static ULONG WINAPI JScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface)
635 {
636     JScript *This = ASPARSEPROC_THIS(iface);
637     return IActiveScript_AddRef(ACTSCRIPT(This));
638 }
639
640 static ULONG WINAPI JScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface)
641 {
642     JScript *This = ASPARSEPROC_THIS(iface);
643     return IActiveScript_Release(ACTSCRIPT(This));
644 }
645
646 static HRESULT WINAPI JScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface,
647         LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName,
648         LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter,
649         DWORD dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
650 {
651     JScript *This = ASPARSEPROC_THIS(iface);
652     parser_ctx_t *parser_ctx;
653     DispatchEx *dispex;
654     HRESULT hres;
655
656     TRACE("(%p)->(%s %s %s %s %p %s %x %u %x %p)\n", This, debugstr_w(pstrCode), debugstr_w(pstrFormalParams),
657           debugstr_w(pstrProcedureName), debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
658           dwSourceContextCookie, ulStartingLineNumber, dwFlags, ppdisp);
659
660     if(This->thread_id != GetCurrentThreadId() || This->ctx->state == SCRIPTSTATE_CLOSED)
661         return E_UNEXPECTED;
662
663     hres = script_parse(This->ctx, pstrCode, &parser_ctx);
664     if(FAILED(hres)) {
665         WARN("Parse failed %08x\n", hres);
666         return hres;
667     }
668
669     hres = create_source_function(parser_ctx, NULL, parser_ctx->source, NULL, NULL, 0, &dispex);
670     parser_release(parser_ctx);
671     if(FAILED(hres))
672         return hres;
673
674     *ppdisp = (IDispatch*)_IDispatchEx_(dispex);
675     return S_OK;
676 }
677
678 #undef ASPARSEPROC_THIS
679
680 static const IActiveScriptParseProcedure2Vtbl JScriptParseProcedureVtbl = {
681     JScriptParseProcedure_QueryInterface,
682     JScriptParseProcedure_AddRef,
683     JScriptParseProcedure_Release,
684     JScriptParseProcedure_ParseProcedureText,
685 };
686
687 #define ACTSCPPROP_THIS(iface) DEFINE_THIS(JScript, IActiveScriptProperty, iface)
688
689 static HRESULT WINAPI JScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv)
690 {
691     JScript *This = ACTSCPPROP_THIS(iface);
692     return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
693 }
694
695 static ULONG WINAPI JScriptProperty_AddRef(IActiveScriptProperty *iface)
696 {
697     JScript *This = ACTSCPPROP_THIS(iface);
698     return IActiveScript_AddRef(ACTSCRIPT(This));
699 }
700
701 static ULONG WINAPI JScriptProperty_Release(IActiveScriptProperty *iface)
702 {
703     JScript *This = ACTSCPPROP_THIS(iface);
704     return IActiveScript_Release(ACTSCRIPT(This));
705 }
706
707 static HRESULT WINAPI JScriptProperty_GetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
708         VARIANT *pvarIndex, VARIANT *pvarValue)
709 {
710     JScript *This = ACTSCPPROP_THIS(iface);
711     FIXME("(%p)->(%x %p %p)\n", This, dwProperty, pvarIndex, pvarValue);
712     return E_NOTIMPL;
713 }
714
715 static HRESULT WINAPI JScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
716         VARIANT *pvarIndex, VARIANT *pvarValue)
717 {
718     JScript *This = ACTSCPPROP_THIS(iface);
719     FIXME("(%p)->(%x %p %p)\n", This, dwProperty, pvarIndex, pvarValue);
720     return E_NOTIMPL;
721 }
722
723 #undef ACTSCPPROP_THIS
724
725 static const IActiveScriptPropertyVtbl JScriptPropertyVtbl = {
726     JScriptProperty_QueryInterface,
727     JScriptProperty_AddRef,
728     JScriptProperty_Release,
729     JScriptProperty_GetProperty,
730     JScriptProperty_SetProperty
731 };
732
733 #define OBJSAFETY_THIS(iface) DEFINE_THIS(JScript, IObjectSafety, iface)
734
735 static HRESULT WINAPI JScriptSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
736 {
737     JScript *This = OBJSAFETY_THIS(iface);
738     return IActiveScript_QueryInterface(ACTSCRIPT(This), riid, ppv);
739 }
740
741 static ULONG WINAPI JScriptSafety_AddRef(IObjectSafety *iface)
742 {
743     JScript *This = OBJSAFETY_THIS(iface);
744     return IActiveScript_AddRef(ACTSCRIPT(This));
745 }
746
747 static ULONG WINAPI JScriptSafety_Release(IObjectSafety *iface)
748 {
749     JScript *This = OBJSAFETY_THIS(iface);
750     return IActiveScript_Release(ACTSCRIPT(This));
751 }
752
753 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
754
755 static HRESULT WINAPI JScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
756         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
757 {
758     JScript *This = OBJSAFETY_THIS(iface);
759
760     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
761
762     if(!pdwSupportedOptions || !pdwEnabledOptions)
763         return E_POINTER;
764
765     *pdwSupportedOptions = SUPPORTED_OPTIONS;
766     *pdwEnabledOptions = This->safeopt;
767
768     return S_OK;
769 }
770
771 static HRESULT WINAPI JScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
772         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
773 {
774     JScript *This = OBJSAFETY_THIS(iface);
775
776     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
777
778     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
779         return E_FAIL;
780
781     This->safeopt = dwEnabledOptions & dwEnabledOptions;
782     return S_OK;
783 }
784
785 #undef OBJSAFETY_THIS
786
787 static const IObjectSafetyVtbl JScriptSafetyVtbl = {
788     JScriptSafety_QueryInterface,
789     JScriptSafety_AddRef,
790     JScriptSafety_Release,
791     JScriptSafety_GetInterfaceSafetyOptions,
792     JScriptSafety_SetInterfaceSafetyOptions
793 };
794
795 HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter,
796                                              REFIID riid, void **ppv)
797 {
798     JScript *ret;
799     HRESULT hres;
800
801     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
802
803     lock_module();
804
805     ret = heap_alloc_zero(sizeof(*ret));
806     if(!ret)
807         return E_OUTOFMEMORY;
808
809     ret->lpIActiveScriptVtbl                 = &JScriptVtbl;
810     ret->lpIActiveScriptParseVtbl            = &JScriptParseVtbl;
811     ret->lpIActiveScriptParseProcedure2Vtbl  = &JScriptParseProcedureVtbl;
812     ret->lpIActiveScriptPropertyVtbl         = &JScriptPropertyVtbl;
813     ret->lpIObjectSafetyVtbl                 = &JScriptSafetyVtbl;
814     ret->ref = 1;
815     ret->safeopt = INTERFACE_USES_DISPEX;
816
817     hres = IActiveScript_QueryInterface(ACTSCRIPT(ret), riid, ppv);
818     IActiveScript_Release(ACTSCRIPT(ret));
819     return hres;
820 }