shell32/tests: Add a few more ShellExecute() file URL tests.
[wine] / dlls / mshtml / script.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 "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "activscp.h"
30 #include "activdbg.h"
31
32 #include "wine/debug.h"
33
34 #include "mshtml_private.h"
35 #include "binding.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
38
39 #ifdef _WIN64
40
41 #define CTXARG_T DWORDLONG
42 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug64Vtbl
43
44 #define IActiveScriptParse_Release IActiveScriptParse64_Release
45 #define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
46 #define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
47 #define IActiveScriptParseProcedure_Release IActiveScriptParseProcedure64_Release
48 #define IActiveScriptParseProcedure_ParseProcedureText IActiveScriptParseProcedure64_ParseProcedureText
49
50 #else
51
52 #define CTXARG_T DWORD
53 #define IActiveScriptSiteDebugVtbl IActiveScriptSiteDebug32Vtbl
54
55 #define IActiveScriptParse_Release IActiveScriptParse32_Release
56 #define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
57 #define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
58 #define IActiveScriptParseProcedure_Release IActiveScriptParseProcedure32_Release
59 #define IActiveScriptParseProcedure_ParseProcedureText IActiveScriptParseProcedure32_ParseProcedureText
60
61 #endif
62
63 static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
64 static const WCHAR emptyW[] = {0};
65
66 struct ScriptHost {
67     IActiveScriptSite              IActiveScriptSite_iface;
68     IActiveScriptSiteInterruptPoll IActiveScriptSiteInterruptPoll_iface;
69     IActiveScriptSiteWindow        IActiveScriptSiteWindow_iface;
70     IActiveScriptSiteDebug         IActiveScriptSiteDebug_iface;
71     IServiceProvider               IServiceProvider_iface;
72
73     LONG ref;
74
75     IActiveScript *script;
76     IActiveScriptParse *parse;
77     IActiveScriptParseProcedure *parse_proc;
78
79     SCRIPTSTATE script_state;
80
81     HTMLInnerWindow *window;
82
83     GUID guid;
84     struct list entry;
85 };
86
87 static void set_script_prop(ScriptHost *script_host, DWORD property, VARIANT *val)
88 {
89     IActiveScriptProperty *script_prop;
90     HRESULT hres;
91
92     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptProperty,
93             (void**)&script_prop);
94     if(FAILED(hres)) {
95         WARN("Could not get IActiveScriptProperty iface: %08x\n", hres);
96         return;
97     }
98
99     hres = IActiveScriptProperty_SetProperty(script_prop, property, NULL, val);
100     IActiveScriptProperty_Release(script_prop);
101     if(FAILED(hres))
102         WARN("SetProperty(%x) failed: %08x\n", property, hres);
103 }
104
105 static BOOL init_script_engine(ScriptHost *script_host)
106 {
107     IObjectSafety *safety;
108     SCRIPTSTATE state;
109     DWORD supported_opts=0, enabled_opts=0;
110     VARIANT var;
111     HRESULT hres;
112
113     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParse, (void**)&script_host->parse);
114     if(FAILED(hres)) {
115         WARN("Could not get IActiveScriptHost: %08x\n", hres);
116         return FALSE;
117     }
118
119     hres = IActiveScript_QueryInterface(script_host->script, &IID_IObjectSafety, (void**)&safety);
120     if(FAILED(hres)) {
121         FIXME("Could not get IObjectSafety: %08x\n", hres);
122         return FALSE;
123     }
124
125     hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported_opts, &enabled_opts);
126     if(FAILED(hres)) {
127         FIXME("GetInterfaceSafetyOptions failed: %08x\n", hres);
128     }else if(!(supported_opts & INTERFACE_USES_DISPEX)) {
129         FIXME("INTERFACE_USES_DISPEX is not supported\n");
130     }else {
131         hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
132                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER,
133                 INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
134         if(FAILED(hres))
135             FIXME("SetInterfaceSafetyOptions failed: %08x\n", hres);
136     }
137
138     IObjectSafety_Release(safety);
139     if(FAILED(hres))
140         return FALSE;
141
142     V_VT(&var) = VT_I4;
143     V_I4(&var) = 1;
144     set_script_prop(script_host, SCRIPTPROP_INVOKEVERSIONING, &var);
145
146     V_VT(&var) = VT_BOOL;
147     V_BOOL(&var) = VARIANT_TRUE;
148     set_script_prop(script_host, SCRIPTPROP_HACK_TRIDENTEVENTSINK, &var);
149
150     hres = IActiveScriptParse_InitNew(script_host->parse);
151     if(FAILED(hres)) {
152         WARN("InitNew failed: %08x\n", hres);
153         return FALSE;
154     }
155
156     hres = IActiveScript_SetScriptSite(script_host->script, &script_host->IActiveScriptSite_iface);
157     if(FAILED(hres)) {
158         WARN("SetScriptSite failed: %08x\n", hres);
159         IActiveScript_Close(script_host->script);
160         return FALSE;
161     }
162
163     hres = IActiveScript_GetScriptState(script_host->script, &state);
164     if(FAILED(hres))
165         WARN("GetScriptState failed: %08x\n", hres);
166     else if(state != SCRIPTSTATE_INITIALIZED)
167         FIXME("state = %x\n", state);
168
169     hres = IActiveScript_SetScriptState(script_host->script, SCRIPTSTATE_STARTED);
170     if(FAILED(hres)) {
171         WARN("Starting script failed: %08x\n", hres);
172         return FALSE;
173     }
174
175     hres = IActiveScript_AddNamedItem(script_host->script, windowW,
176             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
177     if(SUCCEEDED(hres)) {
178         V_VT(&var) = VT_BOOL;
179         V_BOOL(&var) = VARIANT_TRUE;
180         set_script_prop(script_host, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var);
181     }else {
182        WARN("AddNamedItem failed: %08x\n", hres);
183     }
184
185     hres = IActiveScript_QueryInterface(script_host->script, &IID_IActiveScriptParseProcedure2,
186                                         (void**)&script_host->parse_proc);
187     if(FAILED(hres)) {
188         /* FIXME: QI for IActiveScriptParseProcedure */
189         WARN("Could not get IActiveScriptParseProcedure iface: %08x\n", hres);
190     }
191
192     return TRUE;
193 }
194
195 static void release_script_engine(ScriptHost *This)
196 {
197     if(!This->script)
198         return;
199
200     switch(This->script_state) {
201     case SCRIPTSTATE_CONNECTED:
202         IActiveScript_SetScriptState(This->script, SCRIPTSTATE_DISCONNECTED);
203
204     case SCRIPTSTATE_STARTED:
205     case SCRIPTSTATE_DISCONNECTED:
206     case SCRIPTSTATE_INITIALIZED:
207         IActiveScript_Close(This->script);
208
209     default:
210         if(This->parse_proc) {
211             IActiveScriptParseProcedure_Release(This->parse_proc);
212             This->parse_proc = NULL;
213         }
214
215         if(This->parse) {
216             IActiveScriptParse_Release(This->parse);
217             This->parse = NULL;
218         }
219     }
220
221     IActiveScript_Release(This->script);
222     This->script = NULL;
223     This->script_state = SCRIPTSTATE_UNINITIALIZED;
224 }
225
226 void connect_scripts(HTMLInnerWindow *window)
227 {
228     ScriptHost *iter;
229
230     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
231         if(iter->script_state == SCRIPTSTATE_STARTED)
232             IActiveScript_SetScriptState(iter->script, SCRIPTSTATE_CONNECTED);
233     }
234 }
235
236 static inline ScriptHost *impl_from_IActiveScriptSite(IActiveScriptSite *iface)
237 {
238     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSite_iface);
239 }
240
241 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
242 {
243     ScriptHost *This = impl_from_IActiveScriptSite(iface);
244
245     *ppv = NULL;
246
247     if(IsEqualGUID(&IID_IUnknown, riid)) {
248         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
249         *ppv = &This->IActiveScriptSite_iface;
250     }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
251         TRACE("(%p)->(IID_IActiveScriptSite %p)\n", This, ppv);
252         *ppv = &This->IActiveScriptSite_iface;
253     }else if(IsEqualGUID(&IID_IActiveScriptSiteInterruptPoll, riid)) {
254         TRACE("(%p)->(IID_IActiveScriptSiteInterruprtPoll %p)\n", This, ppv);
255         *ppv = &This->IActiveScriptSiteInterruptPoll_iface;
256     }else if(IsEqualGUID(&IID_IActiveScriptSiteWindow, riid)) {
257         TRACE("(%p)->(IID_IActiveScriptSiteWindow %p)\n", This, ppv);
258         *ppv = &This->IActiveScriptSiteWindow_iface;
259     }else if(IsEqualGUID(&IID_IActiveScriptSiteDebug, riid)) {
260         TRACE("(%p)->(IID_IActiveScriptSiteDebug %p)\n", This, ppv);
261         *ppv = &This->IActiveScriptSiteDebug_iface;
262     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
263         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
264         *ppv = &This->IServiceProvider_iface;
265     }else if(IsEqualGUID(&IID_ICanHandleException, riid)) {
266         TRACE("(%p)->(IID_ICanHandleException not supported %p)\n", This, ppv);
267         return E_NOINTERFACE;
268     }else {
269         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
270         return E_NOINTERFACE;
271     }
272
273     IUnknown_AddRef((IUnknown*)*ppv);
274     return S_OK;
275 }
276
277 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
278 {
279     ScriptHost *This = impl_from_IActiveScriptSite(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 ActiveScriptSite_Release(IActiveScriptSite *iface)
288 {
289     ScriptHost *This = impl_from_IActiveScriptSite(iface);
290     LONG ref = InterlockedDecrement(&This->ref);
291
292     TRACE("(%p) ref=%d\n", This, ref);
293
294     if(!ref) {
295         release_script_engine(This);
296         if(This->window)
297             list_remove(&This->entry);
298         heap_free(This);
299     }
300
301     return ref;
302 }
303
304 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
305 {
306     ScriptHost *This = impl_from_IActiveScriptSite(iface);
307
308     TRACE("(%p)->(%p)\n", This, plcid);
309
310     *plcid = GetUserDefaultLCID();
311     return S_OK;
312 }
313
314 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
315         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
316 {
317     ScriptHost *This = impl_from_IActiveScriptSite(iface);
318
319     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_w(pstrName), dwReturnMask, ppiunkItem, ppti);
320
321     if(dwReturnMask != SCRIPTINFO_IUNKNOWN) {
322         FIXME("Unsupported mask %x\n", dwReturnMask);
323         return E_NOTIMPL;
324     }
325
326     *ppiunkItem = NULL;
327
328     if(strcmpW(pstrName, windowW))
329         return DISP_E_MEMBERNOTFOUND;
330
331     if(!This->window)
332         return E_FAIL;
333
334     /* FIXME: Return proxy object */
335     *ppiunkItem = (IUnknown*)&This->window->base.IHTMLWindow2_iface;
336     IUnknown_AddRef(*ppiunkItem);
337
338     return S_OK;
339 }
340
341 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
342 {
343     ScriptHost *This = impl_from_IActiveScriptSite(iface);
344     FIXME("(%p)->(%p)\n", This, pbstrVersion);
345     return E_NOTIMPL;
346 }
347
348 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
349         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
350 {
351     ScriptHost *This = impl_from_IActiveScriptSite(iface);
352     FIXME("(%p)->(%p %p)\n", This, pvarResult, pexcepinfo);
353     return E_NOTIMPL;
354 }
355
356 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
357 {
358     ScriptHost *This = impl_from_IActiveScriptSite(iface);
359
360     TRACE("(%p)->(%x)\n", This, ssScriptState);
361
362     This->script_state = ssScriptState;
363     return S_OK;
364 }
365
366 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
367 {
368     ScriptHost *This = impl_from_IActiveScriptSite(iface);
369     FIXME("(%p)->(%p)\n", This, pscripterror);
370     return E_NOTIMPL;
371 }
372
373 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
374 {
375     ScriptHost *This = impl_from_IActiveScriptSite(iface);
376
377     TRACE("(%p)->()\n", This);
378
379     return S_OK;
380 }
381
382 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
383 {
384     ScriptHost *This = impl_from_IActiveScriptSite(iface);
385
386     TRACE("(%p)->()\n", This);
387
388     return S_OK;
389 }
390
391 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
392     ActiveScriptSite_QueryInterface,
393     ActiveScriptSite_AddRef,
394     ActiveScriptSite_Release,
395     ActiveScriptSite_GetLCID,
396     ActiveScriptSite_GetItemInfo,
397     ActiveScriptSite_GetDocVersionString,
398     ActiveScriptSite_OnScriptTerminate,
399     ActiveScriptSite_OnStateChange,
400     ActiveScriptSite_OnScriptError,
401     ActiveScriptSite_OnEnterScript,
402     ActiveScriptSite_OnLeaveScript
403 };
404
405 static inline ScriptHost *impl_from_IActiveScriptSiteInterruptPoll(IActiveScriptSiteInterruptPoll *iface)
406 {
407     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteInterruptPoll_iface);
408 }
409
410 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryInterface(IActiveScriptSiteInterruptPoll *iface,
411         REFIID riid, void **ppv)
412 {
413     ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
414     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
415 }
416
417 static ULONG WINAPI ActiveScriptSiteInterruptPoll_AddRef(IActiveScriptSiteInterruptPoll *iface)
418 {
419     ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
420     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
421 }
422
423 static ULONG WINAPI ActiveScriptSiteInterruptPoll_Release(IActiveScriptSiteInterruptPoll *iface)
424 {
425     ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
426     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
427 }
428
429 static HRESULT WINAPI ActiveScriptSiteInterruptPoll_QueryContinue(IActiveScriptSiteInterruptPoll *iface)
430 {
431     ScriptHost *This = impl_from_IActiveScriptSiteInterruptPoll(iface);
432
433     TRACE("(%p)\n", This);
434
435     return S_OK;
436 }
437
438 static const IActiveScriptSiteInterruptPollVtbl ActiveScriptSiteInterruptPollVtbl = {
439     ActiveScriptSiteInterruptPoll_QueryInterface,
440     ActiveScriptSiteInterruptPoll_AddRef,
441     ActiveScriptSiteInterruptPoll_Release,
442     ActiveScriptSiteInterruptPoll_QueryContinue
443 };
444
445 static inline ScriptHost *impl_from_IActiveScriptSiteWindow(IActiveScriptSiteWindow *iface)
446 {
447     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteWindow_iface);
448 }
449
450 static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface,
451         REFIID riid, void **ppv)
452 {
453     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
454     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
455 }
456
457 static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
458 {
459     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
460     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
461 }
462
463 static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
464 {
465     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
466     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
467 }
468
469 static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
470 {
471     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
472     FIXME("(%p)->(%p)\n", This, phwnd);
473     return E_NOTIMPL;
474 }
475
476 static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
477 {
478     ScriptHost *This = impl_from_IActiveScriptSiteWindow(iface);
479     FIXME("(%p)->(%x)\n", This, fEnable);
480     return E_NOTIMPL;
481 }
482
483 static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
484     ActiveScriptSiteWindow_QueryInterface,
485     ActiveScriptSiteWindow_AddRef,
486     ActiveScriptSiteWindow_Release,
487     ActiveScriptSiteWindow_GetWindow,
488     ActiveScriptSiteWindow_EnableModeless
489 };
490
491 static inline ScriptHost *impl_from_IActiveScriptSiteDebug(IActiveScriptSiteDebug *iface)
492 {
493     return CONTAINING_RECORD(iface, ScriptHost, IActiveScriptSiteDebug_iface);
494 }
495
496 static HRESULT WINAPI ActiveScriptSiteDebug_QueryInterface(IActiveScriptSiteDebug *iface,
497         REFIID riid, void **ppv)
498 {
499     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
500     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
501 }
502
503 static ULONG WINAPI ActiveScriptSiteDebug_AddRef(IActiveScriptSiteDebug *iface)
504 {
505     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
506     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
507 }
508
509 static ULONG WINAPI ActiveScriptSiteDebug_Release(IActiveScriptSiteDebug *iface)
510 {
511     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
512     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
513 }
514
515 static HRESULT WINAPI ActiveScriptSiteDebug_GetDocumentContextFromPosition(IActiveScriptSiteDebug *iface,
516             CTXARG_T dwSourceContext, ULONG uCharacterOffset, ULONG uNumChars, IDebugDocumentContext **ppsc)
517 {
518     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
519     FIXME("(%p)->(%s %u %u %p)\n", This, wine_dbgstr_longlong(dwSourceContext), uCharacterOffset,
520           uNumChars, ppsc);
521     return E_NOTIMPL;
522 }
523
524 static HRESULT WINAPI ActiveScriptSiteDebug_GetApplication(IActiveScriptSiteDebug *iface, IDebugApplication **ppda)
525 {
526     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
527     FIXME("(%p)->(%p)\n", This, ppda);
528     return E_NOTIMPL;
529 }
530
531 static HRESULT WINAPI ActiveScriptSiteDebug_GetRootApplicationNode(IActiveScriptSiteDebug *iface,
532             IDebugApplicationNode **ppdanRoot)
533 {
534     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
535     FIXME("(%p)->(%p)\n", This, ppdanRoot);
536     return E_NOTIMPL;
537 }
538
539 static HRESULT WINAPI ActiveScriptSiteDebug_OnScriptErrorDebug(IActiveScriptSiteDebug *iface,
540             IActiveScriptErrorDebug *pErrorDebug, BOOL *pfEnterDebugger, BOOL *pfCallOnScriptErrorWhenContinuing)
541 {
542     ScriptHost *This = impl_from_IActiveScriptSiteDebug(iface);
543     FIXME("(%p)->(%p %p %p)\n", This, pErrorDebug, pfEnterDebugger, pfCallOnScriptErrorWhenContinuing);
544     return E_NOTIMPL;
545 }
546
547 static const IActiveScriptSiteDebugVtbl ActiveScriptSiteDebugVtbl = {
548     ActiveScriptSiteDebug_QueryInterface,
549     ActiveScriptSiteDebug_AddRef,
550     ActiveScriptSiteDebug_Release,
551     ActiveScriptSiteDebug_GetDocumentContextFromPosition,
552     ActiveScriptSiteDebug_GetApplication,
553     ActiveScriptSiteDebug_GetRootApplicationNode,
554     ActiveScriptSiteDebug_OnScriptErrorDebug
555 };
556
557 static inline ScriptHost *impl_from_IServiceProvider(IServiceProvider *iface)
558 {
559     return CONTAINING_RECORD(iface, ScriptHost, IServiceProvider_iface);
560 }
561
562 static HRESULT WINAPI ASServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
563 {
564     ScriptHost *This = impl_from_IServiceProvider(iface);
565     return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv);
566 }
567
568 static ULONG WINAPI ASServiceProvider_AddRef(IServiceProvider *iface)
569 {
570     ScriptHost *This = impl_from_IServiceProvider(iface);
571     return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface);
572 }
573
574 static ULONG WINAPI ASServiceProvider_Release(IServiceProvider *iface)
575 {
576     ScriptHost *This = impl_from_IServiceProvider(iface);
577     return IActiveScriptSite_Release(&This->IActiveScriptSite_iface);
578 }
579
580 static HRESULT WINAPI ASServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
581         REFIID riid, void **ppv)
582 {
583     ScriptHost *This = impl_from_IServiceProvider(iface);
584
585     if(IsEqualGUID(&SID_SInternetHostSecurityManager, guidService)) {
586         TRACE("(%p)->(SID_SInternetHostSecurityManager)\n", This);
587
588         if(!This->window || !This->window->doc)
589             return E_NOINTERFACE;
590
591         return IInternetHostSecurityManager_QueryInterface(&This->window->doc->IInternetHostSecurityManager_iface,
592                 riid, ppv);
593     }
594
595     FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
596     return E_NOINTERFACE;
597 }
598
599 static const IServiceProviderVtbl ASServiceProviderVtbl = {
600     ASServiceProvider_QueryInterface,
601     ASServiceProvider_AddRef,
602     ASServiceProvider_Release,
603     ASServiceProvider_QueryService
604 };
605
606 static ScriptHost *create_script_host(HTMLInnerWindow *window, const GUID *guid)
607 {
608     ScriptHost *ret;
609     HRESULT hres;
610
611     ret = heap_alloc_zero(sizeof(*ret));
612     ret->IActiveScriptSite_iface.lpVtbl = &ActiveScriptSiteVtbl;
613     ret->IActiveScriptSiteInterruptPoll_iface.lpVtbl = &ActiveScriptSiteInterruptPollVtbl;
614     ret->IActiveScriptSiteWindow_iface.lpVtbl = &ActiveScriptSiteWindowVtbl;
615     ret->IActiveScriptSiteDebug_iface.lpVtbl = &ActiveScriptSiteDebugVtbl;
616     ret->IServiceProvider_iface.lpVtbl = &ASServiceProviderVtbl;
617     ret->ref = 1;
618     ret->window = window;
619     ret->script_state = SCRIPTSTATE_UNINITIALIZED;
620
621     ret->guid = *guid;
622     list_add_tail(&window->script_hosts, &ret->entry);
623
624     hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
625             &IID_IActiveScript, (void**)&ret->script);
626     if(FAILED(hres))
627         WARN("Could not load script engine: %08x\n", hres);
628     else if(!init_script_engine(ret))
629         release_script_engine(ret);
630
631     return ret;
632 }
633
634 static void parse_text(ScriptHost *script_host, LPCWSTR text)
635 {
636     EXCEPINFO excepinfo;
637     VARIANT var;
638     HRESULT hres;
639
640     static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0};
641
642     TRACE("%s\n", debugstr_w(text));
643
644     VariantInit(&var);
645     memset(&excepinfo, 0, sizeof(excepinfo));
646     TRACE(">>>\n");
647     hres = IActiveScriptParse_ParseScriptText(script_host->parse, text, windowW, NULL, script_endW,
648                                               0, 0, SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE,
649                                               &var, &excepinfo);
650     if(SUCCEEDED(hres))
651         TRACE("<<<\n");
652     else
653         WARN("<<< %08x\n", hres);
654
655 }
656
657 static void parse_extern_script(ScriptHost *script_host, LPCWSTR src)
658 {
659     IMoniker *mon;
660     WCHAR *text;
661     HRESULT hres;
662
663     static const WCHAR wine_schemaW[] = {'w','i','n','e',':'};
664
665     if(strlenW(src) > sizeof(wine_schemaW)/sizeof(WCHAR) && !memcmp(src, wine_schemaW, sizeof(wine_schemaW)))
666         src += sizeof(wine_schemaW)/sizeof(WCHAR);
667
668     hres = CreateURLMoniker(NULL, src, &mon);
669     if(FAILED(hres))
670         return;
671
672     hres = bind_mon_to_wstr(script_host->window, mon, &text);
673     IMoniker_Release(mon);
674     if(FAILED(hres))
675         return;
676
677     parse_text(script_host, text);
678
679     heap_free(text);
680 }
681
682 static void parse_inline_script(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
683 {
684     const PRUnichar *text;
685     nsAString text_str;
686     nsresult nsres;
687
688     nsAString_Init(&text_str, NULL);
689
690     nsres = nsIDOMHTMLScriptElement_GetText(nsscript, &text_str);
691
692     if(NS_SUCCEEDED(nsres)) {
693         nsAString_GetData(&text_str, &text);
694         parse_text(script_host, text);
695     }else {
696         ERR("GetText failed: %08x\n", nsres);
697     }
698
699     nsAString_Finish(&text_str);
700 }
701
702 static void parse_script_elem(ScriptHost *script_host, nsIDOMHTMLScriptElement *nsscript)
703 {
704     const PRUnichar *src;
705     nsAString src_str;
706     nsresult nsres;
707
708     nsAString_Init(&src_str, NULL);
709
710     nsres = nsIDOMHTMLScriptElement_GetSrc(nsscript, &src_str);
711     nsAString_GetData(&src_str, &src);
712
713     if(NS_FAILED(nsres))
714         ERR("GetSrc failed: %08x\n", nsres);
715     else if(*src)
716         parse_extern_script(script_host, src);
717     else
718         parse_inline_script(script_host, nsscript);
719
720     nsAString_Finish(&src_str);
721 }
722
723 static GUID get_default_script_guid(HTMLInnerWindow *window)
724 {
725     /* If not specified, we should use very first script host that was created for the page (or JScript if none) */
726     return list_empty(&window->script_hosts)
727         ? CLSID_JScript
728         : LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry)->guid;
729 }
730
731 static BOOL get_guid_from_type(LPCWSTR type, GUID *guid)
732 {
733     const WCHAR text_javascriptW[] =
734         {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0};
735     const WCHAR text_vbscriptW[] =
736         {'t','e','x','t','/','v','b','s','c','r','i','p','t',0};
737
738     /* FIXME: Handle more types */
739     if(!strcmpiW(type, text_javascriptW)) {
740         *guid = CLSID_JScript;
741     }else if(!strcmpiW(type, text_vbscriptW)) {
742         *guid = CLSID_VBScript;
743     }else {
744         FIXME("Unknown type %s\n", debugstr_w(type));
745         return FALSE;
746     }
747
748     return TRUE;
749 }
750
751 static BOOL get_guid_from_language(LPCWSTR type, GUID *guid)
752 {
753     HRESULT hres;
754
755     hres = CLSIDFromProgID(type, guid);
756     if(FAILED(hres))
757         return FALSE;
758
759     /* FIXME: Check CATID_ActiveScriptParse */
760
761     return TRUE;
762 }
763
764 static BOOL get_script_guid(HTMLInnerWindow *window, nsIDOMHTMLScriptElement *nsscript, GUID *guid)
765 {
766     nsAString attr_str, val_str;
767     BOOL ret = FALSE;
768     nsresult nsres;
769
770     static const PRUnichar languageW[] = {'l','a','n','g','u','a','g','e',0};
771
772     nsAString_Init(&val_str, NULL);
773
774     nsres = nsIDOMHTMLScriptElement_GetType(nsscript, &val_str);
775     if(NS_SUCCEEDED(nsres)) {
776         const PRUnichar *type;
777
778         nsAString_GetData(&val_str, &type);
779         if(*type) {
780             ret = get_guid_from_type(type, guid);
781             nsAString_Finish(&val_str);
782             return ret;
783         }
784     }else {
785         ERR("GetType failed: %08x\n", nsres);
786     }
787
788     nsAString_InitDepend(&attr_str, languageW);
789     nsres = nsIDOMHTMLScriptElement_GetAttribute(nsscript, &attr_str, &val_str);
790     nsAString_Finish(&attr_str);
791     if(NS_SUCCEEDED(nsres)) {
792         const PRUnichar *language;
793
794         nsAString_GetData(&val_str, &language);
795
796         if(*language) {
797             ret = get_guid_from_language(language, guid);
798         }else {
799             *guid = get_default_script_guid(window);
800             ret = TRUE;
801         }
802     }else {
803         ERR("GetAttribute(language) failed: %08x\n", nsres);
804     }
805
806     nsAString_Finish(&val_str);
807
808     return ret;
809 }
810
811 static ScriptHost *get_script_host(HTMLInnerWindow *window, const GUID *guid)
812 {
813     ScriptHost *iter;
814
815     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
816         if(IsEqualGUID(guid, &iter->guid))
817             return iter;
818     }
819
820     return create_script_host(window, guid);
821 }
822
823 void doc_insert_script(HTMLInnerWindow *window, nsIDOMHTMLScriptElement *nsscript)
824 {
825     ScriptHost *script_host;
826     GUID guid;
827
828     if(!get_script_guid(window, nsscript, &guid)) {
829         WARN("Could not find script GUID\n");
830         return;
831     }
832
833     if(IsEqualGUID(&CLSID_JScript, &guid)
834        && (!window->base.outer_window || window->base.outer_window->scriptmode != SCRIPTMODE_ACTIVESCRIPT)) {
835         TRACE("Ignoring JScript\n");
836         return;
837     }
838
839     script_host = get_script_host(window, &guid);
840     if(!script_host)
841         return;
842
843     if(script_host->parse)
844         parse_script_elem(script_host, nsscript);
845 }
846
847 IDispatch *script_parse_event(HTMLInnerWindow *window, LPCWSTR text)
848 {
849     ScriptHost *script_host;
850     GUID guid;
851     const WCHAR *ptr;
852     IDispatch *disp;
853     HRESULT hres;
854
855     static const WCHAR delimiterW[] = {'\"',0};
856
857     TRACE("%s\n", debugstr_w(text));
858
859     for(ptr = text; isalnumW(*ptr); ptr++);
860     if(*ptr == ':') {
861         LPWSTR language;
862         BOOL b;
863
864         language = heap_alloc((ptr-text+1)*sizeof(WCHAR));
865         memcpy(language, text, (ptr-text)*sizeof(WCHAR));
866         language[ptr-text] = 0;
867
868         b = get_guid_from_language(language, &guid);
869
870         heap_free(language);
871
872         if(!b) {
873             WARN("Could not find language\n");
874             return NULL;
875         }
876
877         ptr++;
878     }else {
879         ptr = text;
880         guid = get_default_script_guid(window);
881     }
882
883     if(IsEqualGUID(&CLSID_JScript, &guid)
884        && (!window->base.outer_window || window->base.outer_window->scriptmode != SCRIPTMODE_ACTIVESCRIPT)) {
885         TRACE("Ignoring JScript\n");
886         return NULL;
887     }
888
889     script_host = get_script_host(window, &guid);
890     if(!script_host || !script_host->parse_proc)
891         return NULL;
892
893     hres = IActiveScriptParseProcedure_ParseProcedureText(script_host->parse_proc, ptr, NULL, emptyW,
894             NULL, NULL, delimiterW, 0 /* FIXME */, 0,
895             SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
896     if(FAILED(hres)) {
897         WARN("ParseProcedureText failed: %08x\n", hres);
898         return NULL;
899     }
900
901     TRACE("ret %p\n", disp);
902     return disp;
903 }
904
905 HRESULT exec_script(HTMLInnerWindow *window, const WCHAR *code, const WCHAR *lang, VARIANT *ret)
906 {
907     ScriptHost *script_host;
908     EXCEPINFO ei;
909     GUID guid;
910     HRESULT hres;
911
912     static const WCHAR delimW[] = {'"',0};
913
914     if(!get_guid_from_language(lang, &guid)) {
915         WARN("Could not find script GUID\n");
916         return CO_E_CLASSSTRING;
917     }
918
919     script_host = get_script_host(window, &guid);
920     if(!script_host) {
921         FIXME("No script host\n");
922         return E_FAIL;
923     }
924
925     if(!script_host->parse) {
926         FIXME("script_host->parse == NULL\n");
927         return E_FAIL;
928     }
929
930     memset(&ei, 0, sizeof(ei));
931     TRACE(">>>\n");
932     hres = IActiveScriptParse_ParseScriptText(script_host->parse, code, NULL, NULL, delimW, 0, 0, SCRIPTTEXT_ISVISIBLE, ret, &ei);
933     if(SUCCEEDED(hres))
934         TRACE("<<<\n");
935     else
936         WARN("<<< %08x\n", hres);
937
938     return hres;
939 }
940
941 IDispatch *get_script_disp(ScriptHost *script_host)
942 {
943     IDispatch *disp;
944     HRESULT hres;
945
946     if(!script_host->script)
947         return NULL;
948
949     hres = IActiveScript_GetScriptDispatch(script_host->script, windowW, &disp);
950     if(FAILED(hres))
951         return NULL;
952
953     return disp;
954 }
955
956 BOOL find_global_prop(HTMLInnerWindow *window, BSTR name, DWORD flags, ScriptHost **ret_host, DISPID *ret_id)
957 {
958     IDispatchEx *dispex;
959     IDispatch *disp;
960     ScriptHost *iter;
961     HRESULT hres;
962
963     LIST_FOR_EACH_ENTRY(iter, &window->script_hosts, ScriptHost, entry) {
964         disp = get_script_disp(iter);
965         if(!disp)
966             continue;
967
968         hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
969         if(SUCCEEDED(hres)) {
970             hres = IDispatchEx_GetDispID(dispex, name, flags & (~fdexNameEnsure), ret_id);
971             IDispatchEx_Release(dispex);
972         }else {
973             FIXME("No IDispatchEx\n");
974             hres = E_NOTIMPL;
975         }
976
977         IDispatch_Release(disp);
978         if(SUCCEEDED(hres)) {
979             *ret_host = iter;
980             return TRUE;
981         }
982     }
983
984     return FALSE;
985 }
986
987 static BOOL is_jscript_available(void)
988 {
989     static BOOL available, checked;
990
991     if(!checked) {
992         IUnknown *unk;
993         HRESULT hres = CoGetClassObject(&CLSID_JScript, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk);
994
995         if(SUCCEEDED(hres)) {
996             available = TRUE;
997             IUnknown_Release(unk);
998         }else {
999             available = FALSE;
1000         }
1001         checked = TRUE;
1002     }
1003
1004     return available;
1005 }
1006
1007 void set_script_mode(HTMLOuterWindow *window, SCRIPTMODE mode)
1008 {
1009     nsIWebBrowserSetup *setup;
1010     nsresult nsres;
1011
1012     if(mode == SCRIPTMODE_ACTIVESCRIPT && !is_jscript_available()) {
1013         TRACE("jscript.dll not available\n");
1014         window->scriptmode = SCRIPTMODE_GECKO;
1015         return;
1016     }
1017
1018     window->scriptmode = mode;
1019
1020     if(!window->doc_obj->nscontainer || !window->doc_obj->nscontainer->webbrowser)
1021         return;
1022
1023     nsres = nsIWebBrowser_QueryInterface(window->doc_obj->nscontainer->webbrowser,
1024             &IID_nsIWebBrowserSetup, (void**)&setup);
1025     if(NS_SUCCEEDED(nsres)) {
1026         nsres = nsIWebBrowserSetup_SetProperty(setup, SETUP_ALLOW_JAVASCRIPT,
1027                 window->scriptmode == SCRIPTMODE_GECKO);
1028         nsIWebBrowserSetup_Release(setup);
1029     }
1030
1031     if(NS_FAILED(nsres))
1032         ERR("JavaScript setup failed: %08x\n", nsres);
1033 }
1034
1035 void release_script_hosts(HTMLInnerWindow *window)
1036 {
1037     ScriptHost *iter;
1038
1039     while(!list_empty(&window->script_hosts)) {
1040         iter = LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry);
1041
1042         release_script_engine(iter);
1043         list_remove(&iter->entry);
1044         iter->window = NULL;
1045         IActiveScriptSite_Release(&iter->IActiveScriptSite_iface);
1046     }
1047 }