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