mshtml: Inherit HTMLDocumentNode from HTMLDOMNode.
[wine] / dlls / mshtml / tests / script.c
1 /*
2  * Copyright 2008-2009 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 #define COBJMACROS
20 #define CONST_VTABLE
21
22 #include <wine/test.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "dispex.h"
30 #include "mshtml.h"
31 #include "initguid.h"
32 #include "activscp.h"
33 #include "activdbg.h"
34 #include "objsafe.h"
35 #include "mshtmdid.h"
36
37 DEFINE_GUID(CLSID_IdentityUnmarshal,0x0000001b,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
38
39 #ifdef _WIN64
40
41 #define CTXARG_T DWORDLONG
42 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
43 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_64Vtbl
44
45 #else
46
47 #define CTXARG_T DWORD
48 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
49 #define IActiveScriptParseProcedure2Vtbl IActiveScriptParseProcedure2_32Vtbl
50
51 #endif
52
53 #define DEFINE_EXPECT(func) \
54     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
55
56 #define SET_EXPECT(func) \
57     do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
58
59 #define CHECK_EXPECT2(func) \
60     do { \
61         ok(expect_ ##func, "unexpected call " #func "\n"); \
62         called_ ## func = TRUE; \
63     }while(0)
64
65 #define CHECK_EXPECT(func) \
66     do { \
67         CHECK_EXPECT2(func); \
68         expect_ ## func = FALSE; \
69     }while(0)
70
71 #define CHECK_CALLED(func) \
72     do { \
73         ok(called_ ## func, "expected " #func "\n"); \
74         expect_ ## func = called_ ## func = FALSE; \
75     }while(0)
76
77 #define CHECK_CALLED_BROKEN(func) \
78     do { \
79         ok(called_ ## func || broken(!called_ ## func), "expected " #func "\n"); \
80         expect_ ## func = called_ ## func = FALSE; \
81     }while(0)
82
83 #define CHECK_NOT_CALLED(func) \
84     do { \
85         ok(!called_ ## func, "unexpected " #func "\n"); \
86         expect_ ## func = called_ ## func = FALSE; \
87     }while(0)
88
89 #define CLEAR_CALLED(func) \
90     expect_ ## func = called_ ## func = FALSE
91
92
93 DEFINE_EXPECT(CreateInstance);
94 DEFINE_EXPECT(GetInterfaceSafetyOptions);
95 DEFINE_EXPECT(SetInterfaceSafetyOptions);
96 DEFINE_EXPECT(InitNew);
97 DEFINE_EXPECT(Close);
98 DEFINE_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK);
99 DEFINE_EXPECT(SetProperty_INVOKEVERSIONING);
100 DEFINE_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION);
101 DEFINE_EXPECT(SetScriptSite);
102 DEFINE_EXPECT(GetScriptState);
103 DEFINE_EXPECT(SetScriptState_STARTED);
104 DEFINE_EXPECT(SetScriptState_CONNECTED);
105 DEFINE_EXPECT(SetScriptState_DISCONNECTED);
106 DEFINE_EXPECT(AddNamedItem);
107 DEFINE_EXPECT(ParseScriptText);
108 DEFINE_EXPECT(GetScriptDispatch);
109 DEFINE_EXPECT(funcDisp);
110 DEFINE_EXPECT(script_testprop_d);
111 DEFINE_EXPECT(script_testprop_i);
112
113 #define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}"
114
115 #define DISPID_SCRIPT_TESTPROP   0x100000
116
117 static const GUID CLSID_TestScript =
118     {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}};
119
120 static IHTMLDocument2 *notif_doc;
121 static IDispatchEx *window_dispex;
122 static BOOL doc_complete;
123 static IDispatch *script_disp;
124
125 static const char *debugstr_guid(REFIID riid)
126 {
127     static char buf[50];
128
129     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
130             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
131             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
132             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
133
134     return buf;
135 }
136
137 static int strcmp_wa(LPCWSTR strw, const char *stra)
138 {
139     CHAR buf[512];
140     WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
141     return lstrcmpA(stra, buf);
142 }
143
144 static BSTR a2bstr(const char *str)
145 {
146     BSTR ret;
147     int len;
148
149     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
150     ret = SysAllocStringLen(NULL, len);
151     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
152
153     return ret;
154 }
155
156 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
157         REFIID riid, void**ppv)
158 {
159     if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
160         *ppv = iface;
161         return S_OK;
162     }
163
164     return E_NOINTERFACE;
165 }
166
167 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
168 {
169     return 2;
170 }
171
172 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
173 {
174     return 1;
175 }
176
177 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
178 {
179     if(dispID == DISPID_READYSTATE){
180         BSTR state;
181         HRESULT hres;
182
183         static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0};
184
185         hres = IHTMLDocument2_get_readyState(notif_doc, &state);
186         ok(hres == S_OK, "get_readyState failed: %08x\n", hres);
187
188         if(!lstrcmpW(state, completeW))
189             doc_complete = TRUE;
190
191         SysFreeString(state);
192     }
193
194     return S_OK;
195 }
196
197 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
198 {
199     ok(0, "unexpected call\n");
200     return E_NOTIMPL;
201 }
202
203 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
204     PropertyNotifySink_QueryInterface,
205     PropertyNotifySink_AddRef,
206     PropertyNotifySink_Release,
207     PropertyNotifySink_OnChanged,
208     PropertyNotifySink_OnRequestEdit
209 };
210
211 static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
212
213 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
214 {
215     *ppv = NULL;
216
217     if(IsEqualGUID(riid, &IID_IUnknown)
218        || IsEqualGUID(riid, &IID_IDispatch)
219        || IsEqualGUID(riid, &IID_IDispatchEx))
220         *ppv = iface;
221     else
222         return E_NOINTERFACE;
223
224     return S_OK;
225 }
226
227 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
228 {
229     return 2;
230 }
231
232 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
233 {
234     return 1;
235 }
236
237 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
238 {
239     ok(0, "unexpected call\n");
240     return E_NOTIMPL;
241 }
242
243 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
244                                               LCID lcid, ITypeInfo **ppTInfo)
245 {
246     ok(0, "unexpected call\n");
247     return E_NOTIMPL;
248 }
249
250 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
251                                                 LPOLESTR *rgszNames, UINT cNames,
252                                                 LCID lcid, DISPID *rgDispId)
253 {
254     ok(0, "unexpected call\n");
255     return E_NOTIMPL;
256 }
257
258 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
259                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
260                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
261 {
262     ok(0, "unexpected call\n");
263     return E_NOTIMPL;
264 }
265
266 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
267 {
268     ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
269     return E_NOTIMPL;
270 }
271
272 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
273 {
274     ok(0, "unexpected call\n");
275     return E_NOTIMPL;
276 }
277
278 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
279 {
280     ok(0, "unexpected call\n");
281     return E_NOTIMPL;
282 }
283
284 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
285 {
286     ok(0, "unexpected call\n");
287     return E_NOTIMPL;
288 }
289
290 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
291 {
292     ok(0, "unexpected call\n");
293     return E_NOTIMPL;
294 }
295
296 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
297 {
298     ok(0, "unexpected call\n");
299     return E_NOTIMPL;
300 }
301
302 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
303 {
304     ok(0, "unexpected call\n");
305     return E_NOTIMPL;
306 }
307
308 static HRESULT WINAPI funcDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
309         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
310 {
311     CHECK_EXPECT(funcDisp);
312
313     ok(id == DISPID_VALUE, "id = %d\n", id);
314     ok(lcid == 0, "lcid = %x\n", lcid);
315     ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags);
316     ok(pdp != NULL, "pdp == NULL\n");
317     ok(pdp->cArgs == 2, "pdp->cArgs = %d\n", pdp->cArgs);
318     ok(pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs);
319     ok(pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]);
320     ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg));
321     ok(V_VT(pdp->rgvarg+1) == VT_BOOL, "V_VT(rgvarg[1]) = %d\n", V_VT(pdp->rgvarg));
322     ok(V_BOOL(pdp->rgvarg+1) == VARIANT_TRUE, "V_BOOL(rgvarg[1]) = %x\n", V_BOOL(pdp->rgvarg));
323     ok(pvarRes != NULL, "pvarRes == NULL\n");
324     ok(pei != NULL, "pei == NULL\n");
325     ok(!pspCaller, "pspCaller != NULL\n");
326
327     V_VT(pvarRes) = VT_I4;
328     V_I4(pvarRes) = 100;
329     return S_OK;
330 }
331
332 static IDispatchExVtbl testObjVtbl = {
333     DispatchEx_QueryInterface,
334     DispatchEx_AddRef,
335     DispatchEx_Release,
336     DispatchEx_GetTypeInfoCount,
337     DispatchEx_GetTypeInfo,
338     DispatchEx_GetIDsOfNames,
339     DispatchEx_Invoke,
340     DispatchEx_GetDispID,
341     funcDisp_InvokeEx,
342     DispatchEx_DeleteMemberByName,
343     DispatchEx_DeleteMemberByDispID,
344     DispatchEx_GetMemberProperties,
345     DispatchEx_GetMemberName,
346     DispatchEx_GetNextDispID,
347     DispatchEx_GetNameSpaceParent
348 };
349
350 static IDispatchEx funcDisp = { &testObjVtbl };
351
352 static HRESULT WINAPI scriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
353 {
354     if(!strcmp_wa(bstrName, "testProp")) {
355         CHECK_EXPECT(script_testprop_d);
356         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
357         *pid = DISPID_SCRIPT_TESTPROP;
358         return S_OK;
359     }
360
361     ok(0, "unexpected call\n");
362     return E_NOTIMPL;
363 }
364
365 static HRESULT WINAPI scriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
366         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
367 {
368     switch(id) {
369     case DISPID_SCRIPT_TESTPROP:
370         CHECK_EXPECT(script_testprop_i);
371
372         ok(lcid == 0, "lcid = %x\n", lcid);
373         ok(wFlags == DISPATCH_PROPERTYGET, "wFlags = %x\n", wFlags);
374         ok(pdp != NULL, "pdp == NULL\n");
375         ok(pdp->cArgs == 0, "pdp->cArgs = %d\n", pdp->cArgs);
376         ok(pdp->cNamedArgs == 0, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs);
377         ok(!pdp->rgdispidNamedArgs, "pdp->rgdispidNamedArgs != NULL\n");
378         ok(!pdp->rgvarg, "rgvarg != NULL\n");
379         ok(pvarRes != NULL, "pvarRes == NULL\n");
380         ok(pei != NULL, "pei == NULL\n");
381         ok(!pspCaller, "pspCaller != NULL\n");
382
383         V_VT(pvarRes) = VT_NULL;
384         break;
385     default:
386         ok(0, "unexpected call\n");
387         return E_NOTIMPL;
388     }
389
390     return S_OK;
391 }
392
393 static IDispatchExVtbl scriptDispVtbl = {
394     DispatchEx_QueryInterface,
395     DispatchEx_AddRef,
396     DispatchEx_Release,
397     DispatchEx_GetTypeInfoCount,
398     DispatchEx_GetTypeInfo,
399     DispatchEx_GetIDsOfNames,
400     DispatchEx_Invoke,
401     scriptDisp_GetDispID,
402     scriptDisp_InvokeEx,
403     DispatchEx_DeleteMemberByName,
404     DispatchEx_DeleteMemberByDispID,
405     DispatchEx_GetMemberProperties,
406     DispatchEx_GetMemberName,
407     DispatchEx_GetNextDispID,
408     DispatchEx_GetNameSpaceParent
409 };
410
411 static IDispatchEx scriptDisp = { &scriptDispVtbl };
412
413 static IHTMLDocument2 *create_document(void)
414 {
415     IHTMLDocument2 *doc;
416     HRESULT hres;
417
418     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
419             &IID_IHTMLDocument2, (void**)&doc);
420     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
421
422     return doc;
423 }
424
425 static IHTMLDocument2 *create_doc_with_string(const char *str)
426 {
427     IPersistStreamInit *init;
428     IStream *stream;
429     IHTMLDocument2 *doc;
430     HGLOBAL mem;
431     SIZE_T len;
432
433     notif_doc = doc = create_document();
434     if(!doc)
435         return NULL;
436
437     doc_complete = FALSE;
438     len = strlen(str);
439     mem = GlobalAlloc(0, len);
440     memcpy(mem, str, len);
441     CreateStreamOnHGlobal(mem, TRUE, &stream);
442
443     IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init);
444
445     IPersistStreamInit_Load(init, stream);
446     IPersistStreamInit_Release(init);
447     IStream_Release(stream);
448
449     return doc;
450 }
451
452 static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise)
453 {
454     IConnectionPointContainer *container;
455     IConnectionPoint *cp;
456     DWORD cookie;
457     HRESULT hres;
458
459     hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container);
460     ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
461
462     hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp);
463     IConnectionPointContainer_Release(container);
464     ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
465
466     hres = IConnectionPoint_Advise(cp, unk_advise, &cookie);
467     IConnectionPoint_Release(cp);
468     ok(hres == S_OK, "Advise failed: %08x\n", hres);
469 }
470
471 typedef void (*domtest_t)(IHTMLDocument2*);
472
473 static IHTMLDocument2 *create_and_load_doc(const char *str)
474 {
475     IHTMLDocument2 *doc;
476     IHTMLElement *body = NULL;
477     ULONG ref;
478     MSG msg;
479     HRESULT hres;
480     static const WCHAR ucPtr[] = {'b','a','c','k','g','r','o','u','n','d',0};
481     DISPID dispID = -1;
482     OLECHAR *name;
483
484
485     doc = create_doc_with_string(str);
486     do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
487
488     while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
489         TranslateMessage(&msg);
490         DispatchMessage(&msg);
491     }
492
493     hres = IHTMLDocument2_get_body(doc, &body);
494     ok(hres == S_OK, "get_body failed: %08x\n", hres);
495
496     if(!body) {
497         skip("Could not get document body. Assuming no Gecko installed.\n");
498         ref = IHTMLDocument2_Release(doc);
499         ok(!ref, "ref = %d\n", ref);
500         return NULL;
501     }
502
503     /* Check we can query for function on the IHTMLElementBody interface */
504     name = (WCHAR*)ucPtr;
505     hres = IHTMLElement_GetIDsOfNames(body, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispID);
506     ok(hres == S_OK, "GetIDsOfNames(background) failed %08x\n", hres);
507     ok(dispID == DISPID_IHTMLBODYELEMENT_BACKGROUND, "Incorrect dispID got (%d)\n", dispID);
508
509     IHTMLElement_Release(body);
510     return doc;
511 }
512
513 static IActiveScriptSite *site;
514 static SCRIPTSTATE state;
515
516 static HRESULT WINAPI ObjectSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
517 {
518     *ppv = NULL;
519     ok(0, "unexpected call\n");
520     return E_NOINTERFACE;
521 }
522
523 static ULONG WINAPI ObjectSafety_AddRef(IObjectSafety *iface)
524 {
525     return 2;
526 }
527
528 static ULONG WINAPI ObjectSafety_Release(IObjectSafety *iface)
529 {
530     return 1;
531 }
532
533 static HRESULT WINAPI ObjectSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
534         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
535 {
536     CHECK_EXPECT(GetInterfaceSafetyOptions);
537
538     ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", debugstr_guid(riid));
539     ok(pdwSupportedOptions != NULL, "pdwSupportedOptions == NULL\n");
540     ok(pdwEnabledOptions != NULL, "pdwEnabledOptions == NULL\n");
541
542     *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER;
543     *pdwEnabledOptions = INTERFACE_USES_DISPEX;
544
545     return S_OK;
546 }
547
548 static HRESULT WINAPI ObjectSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
549         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
550 {
551     CHECK_EXPECT(SetInterfaceSafetyOptions);
552
553     ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", debugstr_guid(riid));
554
555     ok(dwOptionSetMask == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
556        "dwOptionSetMask=%x\n", dwOptionSetMask);
557     ok(dwEnabledOptions == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
558        "dwEnabledOptions=%x\n", dwOptionSetMask);
559
560     return S_OK;
561 }
562
563 static const IObjectSafetyVtbl ObjectSafetyVtbl = {
564     ObjectSafety_QueryInterface,
565     ObjectSafety_AddRef,
566     ObjectSafety_Release,
567     ObjectSafety_GetInterfaceSafetyOptions,
568     ObjectSafety_SetInterfaceSafetyOptions
569 };
570
571 static IObjectSafety ObjectSafety = { &ObjectSafetyVtbl };
572
573 static HRESULT WINAPI ActiveScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv)
574 {
575     *ppv = NULL;
576     ok(0, "unexpected call\n");
577     return E_NOINTERFACE;
578 }
579
580 static ULONG WINAPI ActiveScriptProperty_AddRef(IActiveScriptProperty *iface)
581 {
582     return 2;
583 }
584
585 static ULONG WINAPI ActiveScriptProperty_Release(IActiveScriptProperty *iface)
586 {
587     return 1;
588 }
589
590 static HRESULT WINAPI ActiveScriptProperty_GetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
591         VARIANT *pvarIndex, VARIANT *pvarValue)
592 {
593     ok(0, "unexpected call\n");
594     return E_NOTIMPL;
595 }
596
597 static HRESULT WINAPI ActiveScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
598         VARIANT *pvarIndex, VARIANT *pvarValue)
599 {
600     switch(dwProperty) {
601     case SCRIPTPROP_HACK_TRIDENTEVENTSINK:
602         CHECK_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK);
603         ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue)=%d\n", V_VT(pvarValue));
604         ok(V_BOOL(pvarValue) == VARIANT_TRUE, "V_BOOL(pvarValue)=%x\n", V_BOOL(pvarValue));
605         break;
606     case SCRIPTPROP_INVOKEVERSIONING:
607         CHECK_EXPECT(SetProperty_INVOKEVERSIONING);
608         ok(V_VT(pvarValue) == VT_I4, "V_VT(pvarValue)=%d\n", V_VT(pvarValue));
609         ok(V_I4(pvarValue) == 1, "V_I4(pvarValue)=%d\n", V_I4(pvarValue));
610         break;
611     case SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION:
612         CHECK_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION);
613         ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue)=%d\n", V_VT(pvarValue));
614         ok(V_BOOL(pvarValue) == VARIANT_TRUE, "V_BOOL(pvarValue)=%x\n", V_BOOL(pvarValue));
615         break;
616     default:
617         ok(0, "unexpected property %x\n", dwProperty);
618         return E_NOTIMPL;
619     }
620
621     ok(!pvarIndex, "pvarIndex != NULL\n");
622     ok(pvarValue != NULL, "pvarValue == NULL\n");
623
624     return S_OK;
625 }
626
627 static const IActiveScriptPropertyVtbl ActiveScriptPropertyVtbl = {
628     ActiveScriptProperty_QueryInterface,
629     ActiveScriptProperty_AddRef,
630     ActiveScriptProperty_Release,
631     ActiveScriptProperty_GetProperty,
632     ActiveScriptProperty_SetProperty
633 };
634
635 static IActiveScriptProperty ActiveScriptProperty = { &ActiveScriptPropertyVtbl };
636
637 static HRESULT WINAPI ActiveScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv)
638 {
639     *ppv = NULL;
640     ok(0, "unexpected call\n");
641     return E_NOINTERFACE;
642 }
643
644 static ULONG WINAPI ActiveScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface)
645 {
646     return 2;
647 }
648
649 static ULONG WINAPI ActiveScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface)
650 {
651     return 1;
652 }
653
654 static HRESULT WINAPI ActiveScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface,
655         LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName,
656         LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter,
657         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
658 {
659     ok(0, "unexpected call\n");
660     return E_NOTIMPL;
661 }
662
663 static const IActiveScriptParseProcedure2Vtbl ActiveScriptParseProcedureVtbl = {
664     ActiveScriptParseProcedure_QueryInterface,
665     ActiveScriptParseProcedure_AddRef,
666     ActiveScriptParseProcedure_Release,
667     ActiveScriptParseProcedure_ParseProcedureText
668 };
669
670 static IActiveScriptParseProcedure2 ActiveScriptParseProcedure = { &ActiveScriptParseProcedureVtbl };
671
672 static HRESULT WINAPI ActiveScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
673 {
674     *ppv = NULL;
675     ok(0, "unexpected call\n");
676     return E_NOINTERFACE;
677 }
678
679 static ULONG WINAPI ActiveScriptParse_AddRef(IActiveScriptParse *iface)
680 {
681     return 2;
682 }
683
684 static ULONG WINAPI ActiveScriptParse_Release(IActiveScriptParse *iface)
685 {
686     return 1;
687 }
688
689 static HRESULT WINAPI ActiveScriptParse_InitNew(IActiveScriptParse *iface)
690 {
691     CHECK_EXPECT(InitNew);
692     return S_OK;
693 }
694
695 static HRESULT WINAPI ActiveScriptParse_AddScriptlet(IActiveScriptParse *iface,
696         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
697         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
698         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
699         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
700 {
701     ok(0, "unexpected call\n");
702     return E_NOTIMPL;
703 }
704
705 static HRESULT dispex_propput(IDispatchEx *obj, DISPID id, VARIANT *var)
706 {
707     DISPID propput_arg = DISPID_PROPERTYPUT;
708     DISPPARAMS dp = {var, &propput_arg, 1, 1};
709     EXCEPINFO ei = {0};
710
711     return IDispatchEx_InvokeEx(obj, id, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dp, NULL, &ei, NULL);
712 }
713
714 static void test_func(IDispatchEx *obj)
715 {
716     DISPID id;
717     IDispatchEx *dispex;
718     IDispatch *disp;
719     EXCEPINFO ei;
720     DISPPARAMS dp;
721     BSTR str;
722     VARIANT var;
723     HRESULT hres;
724
725     str = a2bstr("toString");
726     hres = IDispatchEx_GetDispID(obj, str, fdexNameCaseSensitive, &id);
727     SysFreeString(str);
728     ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
729     ok(id == DISPID_IOMNAVIGATOR_TOSTRING, "id = %x\n", id);
730
731     memset(&dp, 0, sizeof(dp));
732     memset(&ei, 0, sizeof(ei));
733     VariantInit(&var);
734     hres = IDispatchEx_InvokeEx(obj, id, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dp, &var, &ei, NULL);
735     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
736     ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var));
737     ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n");
738     disp = V_DISPATCH(&var);
739
740     hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
741     IDispatch_Release(disp);
742     ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres);
743
744     /* FIXME: Test InvokeEx(DISPATCH_METHOD) */
745
746     memset(&dp, 0, sizeof(dp));
747     memset(&ei, 0, sizeof(ei));
748     VariantInit(&var);
749     hres = IDispatchEx_Invoke(dispex, DISPID_VALUE, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dp, &var, &ei, NULL);
750     ok(hres == S_OK || broken(E_ACCESSDENIED), "InvokeEx failed: %08x\n", hres);
751     if(SUCCEEDED(hres)) {
752         ok(V_VT(&var) == VT_BSTR, "V_VT(var)=%d\n", V_VT(&var));
753         ok(!strcmp_wa(V_BSTR(&var), "[object]"), "V_BSTR(var) = %s\n", wine_dbgstr_w(V_BSTR(&var)));
754         VariantClear(&var);
755     }
756
757     V_VT(&var) = VT_I4;
758     V_I4(&var) = 100;
759     hres = dispex_propput(obj, id, &var);
760     ok(hres == E_NOTIMPL, "InvokeEx failed: %08x\n", hres);
761
762     IDispatchEx_Release(dispex);
763 }
764
765 static void test_nextdispid(IDispatchEx *dispex)
766 {
767     DISPID last_id = DISPID_STARTENUM, id, dyn_id;
768     BSTR name;
769     VARIANT var;
770     HRESULT hres;
771
772     name = a2bstr("dynVal");
773     hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive|fdexNameEnsure, &dyn_id);
774     ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
775     SysFreeString(name);
776
777     V_VT(&var) = VT_EMPTY;
778     hres = dispex_propput(dispex, dyn_id, &var);
779
780     while(last_id != dyn_id) {
781         hres = IDispatchEx_GetNextDispID(dispex, fdexEnumAll, last_id, &id);
782         ok(hres == S_OK, "GetNextDispID returned: %08x\n", hres);
783         ok(id != DISPID_STARTENUM, "id == DISPID_STARTENUM\n");
784         ok(id != DISPID_IOMNAVIGATOR_TOSTRING, "id == DISPID_IOMNAVIGATOR_TOSTRING\n");
785
786         hres = IDispatchEx_GetMemberName(dispex, id, &name);
787         ok(hres == S_OK, "GetMemberName failed: %08x\n", hres);
788
789         if(id == dyn_id)
790             ok(!strcmp_wa(name, "dynVal"), "name = %s\n", wine_dbgstr_w(name));
791         else if(id == DISPID_IOMNAVIGATOR_PLATFORM)
792             ok(!strcmp_wa(name, "platform"), "name = %s\n", wine_dbgstr_w(name));
793
794         SysFreeString(name);
795         last_id = id;
796     }
797
798     hres = IDispatchEx_GetNextDispID(dispex, 0, id, &id);
799     ok(hres == S_FALSE, "GetNextDispID returned: %08x\n", hres);
800     ok(id == DISPID_STARTENUM, "id != DISPID_STARTENUM\n");
801 }
802
803 static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *iface,
804         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
805         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
806         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
807 {
808     IDispatchEx *document, *dispex;
809     IHTMLWindow2 *window;
810     IOmNavigator *navigator;
811     IUnknown *unk;
812     VARIANT var, arg;
813     DISPPARAMS dp;
814     EXCEPINFO ei;
815     DISPID id;
816     BSTR tmp;
817     HRESULT hres;
818
819     static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
820     static const WCHAR testW[] = {'t','e','s','t',0};
821     static const WCHAR funcW[] = {'f','u','n','c',0};
822
823     CHECK_EXPECT(ParseScriptText);
824
825     SET_EXPECT(GetScriptDispatch);
826
827     tmp = SysAllocString(documentW);
828     hres = IDispatchEx_GetDispID(window_dispex, tmp, fdexNameCaseSensitive, &id);
829     SysFreeString(tmp);
830     ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres);
831     ok(id == DISPID_IHTMLWINDOW2_DOCUMENT, "id=%x\n", id);
832
833     CHECK_CALLED(GetScriptDispatch);
834
835     VariantInit(&var);
836     memset(&dp, 0, sizeof(dp));
837     memset(&ei, 0, sizeof(ei));
838
839     hres = IDispatchEx_InvokeEx(window_dispex, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL);
840     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
841     ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var));
842     ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(&var) == NULL\n");
843
844     hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IDispatchEx, (void**)&document);
845     VariantClear(&var);
846     ok(hres == S_OK, "Could not get DispatchEx: %08x\n", hres);
847
848     tmp = SysAllocString(testW);
849     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive, &id);
850     ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(document) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
851     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive | fdexNameImplicit, &id);
852     ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(document) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
853     SysFreeString(tmp);
854
855     id = 0;
856     tmp = SysAllocString(testW);
857     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive|fdexNameEnsure, &id);
858     SysFreeString(tmp);
859     ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres);
860     ok(id, "id == 0\n");
861
862     V_VT(&var) = VT_I4;
863     V_I4(&var) = 100;
864     hres = dispex_propput(document, id, &var);
865     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
866
867     tmp = SysAllocString(testW);
868     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive, &id);
869     SysFreeString(tmp);
870     ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres);
871
872     VariantInit(&var);
873     memset(&dp, 0, sizeof(dp));
874     memset(&ei, 0, sizeof(ei));
875     hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL);
876     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
877     ok(V_VT(&var) == VT_I4, "V_VT(var)=%d\n", V_VT(&var));
878     ok(V_I4(&var) == 100, "V_I4(&var) == NULL\n");
879
880     unk = (void*)0xdeadbeef;
881     hres = IDispatchEx_GetNameSpaceParent(window_dispex, &unk);
882     ok(hres == S_OK, "GetNameSpaceParent failed: %08x\n", hres);
883     ok(!unk, "unk=%p, expected NULL\n", unk);
884
885     id = 0;
886     tmp = SysAllocString(funcW);
887     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive|fdexNameEnsure, &id);
888     SysFreeString(tmp);
889     ok(hres == S_OK, "GetDispID(func) failed: %08x\n", hres);
890     ok(id, "id == 0\n");
891
892     dp.cArgs = 1;
893     dp.rgvarg = &var;
894     dp.cNamedArgs = 0;
895     dp.rgdispidNamedArgs = NULL;
896     V_VT(&var) = VT_DISPATCH;
897     V_DISPATCH(&var) = (IDispatch*)&funcDisp;
898     hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYPUT, &dp, NULL, &ei, NULL);
899     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
900
901     VariantInit(&var);
902     memset(&dp, 0, sizeof(dp));
903     memset(&ei, 0, sizeof(ei));
904     V_VT(&arg) = VT_BOOL;
905     V_BOOL(&arg) = VARIANT_TRUE;
906     dp.cArgs = 1;
907     dp.rgvarg = &arg;
908
909     SET_EXPECT(funcDisp);
910     hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_FUNC, &dp, &var, &ei, NULL);
911     CHECK_CALLED(funcDisp);
912
913     ok(hres == S_OK, "InvokeEx(INVOKE_FUNC) failed: %08x\n", hres);
914     ok(V_VT(&var) == VT_I4, "V_VT(var)=%d\n", V_VT(&var));
915     ok(V_I4(&var) == 100, "V_I4(&var) == NULL\n");
916
917     IDispatchEx_Release(document);
918
919     hres = IDispatchEx_QueryInterface(window_dispex, &IID_IHTMLWindow2, (void**)&window);
920     ok(hres == S_OK, "Could not get IHTMLWindow2 iface: %08x\n", hres);
921
922     hres = IHTMLWindow2_get_navigator(window, &navigator);
923     IHTMLWindow2_Release(window);
924     ok(hres == S_OK, "get_navigator failed: %08x\n", hres);
925
926     hres = IOmNavigator_QueryInterface(navigator, &IID_IDispatchEx, (void**)&dispex);
927     IOmNavigator_Release(navigator);
928     ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres);
929
930     test_func(dispex);
931     test_nextdispid(dispex);
932     IDispatchEx_Release(dispex);
933
934     script_disp = (IDispatch*)&scriptDisp;
935
936     SET_EXPECT(GetScriptDispatch);
937     SET_EXPECT(script_testprop_d);
938     tmp = a2bstr("testProp");
939     hres = IDispatchEx_GetDispID(window_dispex, tmp, fdexNameCaseSensitive, &id);
940     ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
941     ok(id != DISPID_SCRIPT_TESTPROP, "id == DISPID_SCRIPT_TESTPROP\n");
942     CHECK_CALLED(GetScriptDispatch);
943     CHECK_CALLED(script_testprop_d);
944     SysFreeString(tmp);
945
946     tmp = a2bstr("testProp");
947     hres = IDispatchEx_GetDispID(window_dispex, tmp, fdexNameCaseSensitive, &id);
948     ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
949     ok(id != DISPID_SCRIPT_TESTPROP, "id == DISPID_SCRIPT_TESTPROP\n");
950     SysFreeString(tmp);
951
952     SET_EXPECT(GetScriptDispatch);
953     SET_EXPECT(script_testprop_i);
954     memset(&ei, 0, sizeof(ei));
955     memset(&dp, 0, sizeof(dp));
956     hres = IDispatchEx_InvokeEx(window_dispex, id, 0, DISPATCH_PROPERTYGET, &dp, &var, &ei, NULL);
957     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
958     ok(V_VT(&var) == VT_NULL, "V_VT(var) = %d\n", V_VT(&var));
959     CHECK_CALLED(GetScriptDispatch);
960     CHECK_CALLED(script_testprop_i);
961
962     return S_OK;
963 }
964
965 static const IActiveScriptParseVtbl ActiveScriptParseVtbl = {
966     ActiveScriptParse_QueryInterface,
967     ActiveScriptParse_AddRef,
968     ActiveScriptParse_Release,
969     ActiveScriptParse_InitNew,
970     ActiveScriptParse_AddScriptlet,
971     ActiveScriptParse_ParseScriptText
972 };
973
974 static IActiveScriptParse ActiveScriptParse = { &ActiveScriptParseVtbl };
975
976 static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
977 {
978     *ppv = NULL;
979
980     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IActiveScript, riid)) {
981         *ppv = iface;
982         return S_OK;
983     }
984
985     if(IsEqualGUID(&IID_IActiveScriptParse, riid)) {
986         *ppv = &ActiveScriptParse;
987         return S_OK;
988     }
989
990     if(IsEqualGUID(&IID_IActiveScriptParseProcedure2, riid)) {
991         *ppv = &ActiveScriptParseProcedure;
992         return S_OK;
993     }
994
995     if(IsEqualGUID(&IID_IActiveScriptProperty, riid)) {
996         *ppv = &ActiveScriptProperty;
997         return S_OK;
998     }
999
1000     if(IsEqualGUID(&IID_IObjectSafety, riid)) {
1001         *ppv = &ObjectSafety;
1002         return S_OK;
1003     }
1004
1005     if(IsEqualGUID(&IID_IActiveScriptDebug, riid))
1006         return E_NOINTERFACE;
1007
1008     ok(0, "unexpected riid %s\n", debugstr_guid(riid));
1009     return E_NOINTERFACE;
1010 }
1011
1012 static ULONG WINAPI ActiveScript_AddRef(IActiveScript *iface)
1013 {
1014     return 2;
1015 }
1016
1017 static ULONG WINAPI ActiveScript_Release(IActiveScript *iface)
1018 {
1019     return 1;
1020 }
1021
1022 static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
1023 {
1024     IActiveScriptSiteInterruptPoll *poll;
1025     IActiveScriptSiteDebug *debug;
1026     IServiceProvider *service;
1027     ICanHandleException *canexpection;
1028     LCID lcid;
1029     HRESULT hres;
1030
1031     CHECK_EXPECT(SetScriptSite);
1032
1033     ok(pass != NULL, "pass == NULL\n");
1034
1035     hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteInterruptPoll, (void**)&poll);
1036     ok(hres == S_OK, "Could not get IActiveScriptSiteInterruptPoll interface: %08x\n", hres);
1037     if(FAILED(hres))
1038         IActiveScriptSiteInterruptPoll_Release(poll);
1039
1040     hres = IActiveScriptSite_GetLCID(pass, &lcid);
1041     ok(hres == S_OK, "GetLCID failed: %08x\n", hres);
1042
1043     hres = IActiveScriptSite_OnStateChange(pass, (state = SCRIPTSTATE_INITIALIZED));
1044     ok(hres == S_OK, "OnStateChange failed: %08x\n", hres);
1045
1046     hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteDebug, (void**)&debug);
1047     ok(hres == S_OK, "Could not get IActiveScriptSiteDebug interface: %08x\n", hres);
1048     if(SUCCEEDED(hres))
1049         IActiveScriptSiteDebug32_Release(debug);
1050
1051     hres = IActiveScriptSite_QueryInterface(pass, &IID_ICanHandleException, (void**)&canexpection);
1052     ok(hres == E_NOINTERFACE, "Could not get IID_ICanHandleException interface: %08x\n", hres);
1053
1054     hres = IActiveScriptSite_QueryInterface(pass, &IID_IServiceProvider, (void**)&service);
1055     todo_wine ok(hres == S_OK, "Could not get IServiceProvider interface: %08x\n", hres);
1056     if(SUCCEEDED(hres))
1057         IServiceProvider_Release(service);
1058
1059     site = pass;
1060     IActiveScriptSite_AddRef(site);
1061     return S_OK;
1062 }
1063
1064 static HRESULT WINAPI ActiveScript_GetScriptSite(IActiveScript *iface, REFIID riid,
1065                                             void **ppvObject)
1066 {
1067     ok(0, "unexpected call\n");
1068     return E_NOTIMPL;
1069 }
1070
1071 static HRESULT WINAPI ActiveScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
1072 {
1073     HRESULT hres;
1074
1075     switch(ss) {
1076     case SCRIPTSTATE_STARTED:
1077         CHECK_EXPECT(SetScriptState_STARTED);
1078         break;
1079     case SCRIPTSTATE_CONNECTED:
1080         CHECK_EXPECT(SetScriptState_CONNECTED);
1081         break;
1082     case SCRIPTSTATE_DISCONNECTED:
1083         CHECK_EXPECT(SetScriptState_DISCONNECTED);
1084         break;
1085     default:
1086         ok(0, "unexpected state %d\n", ss);
1087         return E_NOTIMPL;
1088     }
1089
1090     hres = IActiveScriptSite_OnStateChange(site, (state = ss));
1091     return S_OK;
1092 }
1093
1094 static HRESULT WINAPI ActiveScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
1095 {
1096     CHECK_EXPECT(GetScriptState);
1097
1098     *pssState = state;
1099     return S_OK;
1100 }
1101
1102 static HRESULT WINAPI ActiveScript_Close(IActiveScript *iface)
1103 {
1104     CHECK_EXPECT(Close);
1105     return E_NOTIMPL;
1106 }
1107
1108 static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface,
1109         LPCOLESTR pstrName, DWORD dwFlags)
1110 {
1111     IDispatch *disp;
1112     IUnknown *unk = NULL, *unk2;
1113     HRESULT hres;
1114
1115     static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
1116
1117     static const IID unknown_iid = {0x719C3050,0xF9D3,0x11CF,{0xA4,0x93,0x00,0x40,0x05,0x23,0xA8,0xA0}};
1118
1119     CHECK_EXPECT(AddNamedItem);
1120
1121     ok(!lstrcmpW(pstrName, windowW), "pstrName=%s\n", wine_dbgstr_w(pstrName));
1122     ok(dwFlags == (SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS), "dwFlags=%x\n", dwFlags);
1123
1124     hres = IActiveScriptSite_GetItemInfo(site, windowW, SCRIPTINFO_IUNKNOWN, &unk, NULL);
1125     ok(hres == S_OK, "GetItemInfo failed: %08x\n", hres);
1126     ok(unk != NULL, "unk == NULL\n");
1127
1128     hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
1129     ok(hres == S_OK, "Could not get IDispatch interface: %08x\n", hres);
1130     if(SUCCEEDED(hres))
1131         IDispatch_Release(disp);
1132
1133     hres = IUnknown_QueryInterface(unk, &unknown_iid, (void**)&unk2);
1134     ok(hres == E_NOINTERFACE, "Got ?? interface: %p\n", unk2);
1135     if(SUCCEEDED(hres))
1136         IUnknown_Release(unk2);
1137
1138     hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&window_dispex);
1139     ok(hres == S_OK, "Could not get IDispatchEx interface: %08x\n", hres);
1140
1141     IUnknown_Release(unk);
1142     return S_OK;
1143 }
1144
1145 static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
1146                                          DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
1147 {
1148     ok(0, "unexpected call\n");
1149     return E_NOTIMPL;
1150 }
1151
1152 static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
1153                                                 IDispatch **ppdisp)
1154 {
1155     CHECK_EXPECT(GetScriptDispatch);
1156
1157     ok(!strcmp_wa(pstrItemName, "window"), "pstrItemName = %s\n", wine_dbgstr_w(pstrItemName));
1158
1159     if(!script_disp)
1160         return E_NOTIMPL;
1161
1162     *ppdisp = script_disp;
1163     return S_OK;
1164 }
1165
1166 static HRESULT WINAPI ActiveScript_GetCurrentScriptThreadID(IActiveScript *iface,
1167                                                        SCRIPTTHREADID *pstridThread)
1168 {
1169     ok(0, "unexpected call\n");
1170     return E_NOTIMPL;
1171 }
1172
1173 static HRESULT WINAPI ActiveScript_GetScriptThreadID(IActiveScript *iface,
1174                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
1175 {
1176     ok(0, "unexpected call\n");
1177     return E_NOTIMPL;
1178 }
1179
1180 static HRESULT WINAPI ActiveScript_GetScriptThreadState(IActiveScript *iface,
1181         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
1182 {
1183     ok(0, "unexpected call\n");
1184     return E_NOTIMPL;
1185 }
1186
1187 static HRESULT WINAPI ActiveScript_InterruptScriptThread(IActiveScript *iface,
1188         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
1189 {
1190     ok(0, "unexpected call\n");
1191     return E_NOTIMPL;
1192 }
1193
1194 static HRESULT WINAPI ActiveScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
1195 {
1196     ok(0, "unexpected call\n");
1197     return E_NOTIMPL;
1198 }
1199
1200 static const IActiveScriptVtbl ActiveScriptVtbl = {
1201     ActiveScript_QueryInterface,
1202     ActiveScript_AddRef,
1203     ActiveScript_Release,
1204     ActiveScript_SetScriptSite,
1205     ActiveScript_GetScriptSite,
1206     ActiveScript_SetScriptState,
1207     ActiveScript_GetScriptState,
1208     ActiveScript_Close,
1209     ActiveScript_AddNamedItem,
1210     ActiveScript_AddTypeLib,
1211     ActiveScript_GetScriptDispatch,
1212     ActiveScript_GetCurrentScriptThreadID,
1213     ActiveScript_GetScriptThreadID,
1214     ActiveScript_GetScriptThreadState,
1215     ActiveScript_InterruptScriptThread,
1216     ActiveScript_Clone
1217 };
1218
1219 static IActiveScript ActiveScript = { &ActiveScriptVtbl };
1220
1221 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
1222 {
1223     *ppv = NULL;
1224
1225     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
1226         *ppv = iface;
1227         return S_OK;
1228     }
1229
1230     if(IsEqualGUID(&IID_IMarshal, riid))
1231         return E_NOINTERFACE;
1232     if(IsEqualGUID(&CLSID_IdentityUnmarshal, riid))
1233         return E_NOINTERFACE;
1234
1235     ok(0, "unexpected riid %s\n", debugstr_guid(riid));
1236     return E_NOTIMPL;
1237 }
1238
1239 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
1240 {
1241     return 2;
1242 }
1243
1244 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
1245 {
1246     return 1;
1247 }
1248
1249 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
1250 {
1251     CHECK_EXPECT(CreateInstance);
1252
1253     ok(!outer, "outer = %p\n", outer);
1254     ok(IsEqualGUID(&IID_IActiveScript, riid), "unexpected riid %s\n", debugstr_guid(riid));
1255     *ppv = &ActiveScript;
1256     return S_OK;
1257 }
1258
1259 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
1260 {
1261     ok(0, "unexpected call\n");
1262     return S_OK;
1263 }
1264
1265 static const IClassFactoryVtbl ClassFactoryVtbl = {
1266     ClassFactory_QueryInterface,
1267     ClassFactory_AddRef,
1268     ClassFactory_Release,
1269     ClassFactory_CreateInstance,
1270     ClassFactory_LockServer
1271 };
1272
1273 static IClassFactory script_cf = { &ClassFactoryVtbl };
1274
1275 static const char simple_script_str[] =
1276     "<html><head></head><body>"
1277     "<script language=\"TestScript\">simple script</script>"
1278     "</body></html>";
1279
1280 static void test_simple_script(void)
1281 {
1282     IHTMLDocument2 *doc;
1283
1284     SET_EXPECT(CreateInstance);
1285     SET_EXPECT(GetInterfaceSafetyOptions);
1286     SET_EXPECT(SetInterfaceSafetyOptions);
1287     SET_EXPECT(SetProperty_INVOKEVERSIONING); /* IE8 */
1288     SET_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK);
1289     SET_EXPECT(InitNew);
1290     SET_EXPECT(SetScriptSite);
1291     SET_EXPECT(GetScriptState);
1292     SET_EXPECT(SetScriptState_STARTED);
1293     SET_EXPECT(AddNamedItem);
1294     SET_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION); /* IE8 */
1295     SET_EXPECT(ParseScriptText);
1296     SET_EXPECT(SetScriptState_CONNECTED);
1297
1298     doc = create_and_load_doc(simple_script_str);
1299     if(!doc) return;
1300
1301     CHECK_CALLED(CreateInstance);
1302     CHECK_CALLED(GetInterfaceSafetyOptions);
1303     CHECK_CALLED(SetInterfaceSafetyOptions);
1304     CHECK_CALLED_BROKEN(SetProperty_INVOKEVERSIONING); /* IE8 */
1305     CHECK_CALLED(SetProperty_HACK_TRIDENTEVENTSINK);
1306     CHECK_CALLED(InitNew);
1307     CHECK_CALLED(SetScriptSite);
1308     CHECK_CALLED(GetScriptState);
1309     CHECK_CALLED(SetScriptState_STARTED);
1310     CHECK_CALLED(AddNamedItem);
1311     CHECK_CALLED_BROKEN(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION); /* IE8 */
1312     CHECK_CALLED(ParseScriptText);
1313     CHECK_CALLED(SetScriptState_CONNECTED);
1314
1315     if(site)
1316         IActiveScriptSite_Release(site);
1317     if(window_dispex)
1318         IDispatchEx_Release(window_dispex);
1319
1320     SET_EXPECT(SetScriptState_DISCONNECTED);
1321     SET_EXPECT(Close);
1322
1323     IHTMLDocument2_Release(doc);
1324
1325     CHECK_CALLED(SetScriptState_DISCONNECTED);
1326     CHECK_CALLED(Close);
1327 }
1328
1329 static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
1330 {
1331     HKEY hkey;
1332     DWORD res;
1333
1334     if(!init) {
1335         RegDeleteKey(HKEY_CLASSES_ROOT, key_name);
1336         return TRUE;
1337     }
1338
1339     res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey);
1340     if(res != ERROR_SUCCESS)
1341         return FALSE;
1342
1343     if(def_value)
1344         res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value));
1345
1346     RegCloseKey(hkey);
1347
1348     return res == ERROR_SUCCESS;
1349 }
1350
1351 static BOOL init_registry(BOOL init)
1352 {
1353     return init_key("TestScript\\CLSID", TESTSCRIPT_CLSID, init)
1354         && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A1-9847-11CF-8F20-00805F2CD064}",
1355                     NULL, init)
1356         && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A2-9847-11CF-8F20-00805F2CD064}",
1357                     NULL, init);
1358 }
1359
1360 static BOOL register_script_engine(void)
1361 {
1362     DWORD regid;
1363     HRESULT hres;
1364
1365     if(!init_registry(TRUE)) {
1366         init_registry(FALSE);
1367         return FALSE;
1368     }
1369
1370     hres = CoRegisterClassObject(&CLSID_TestScript, (IUnknown *)&script_cf,
1371                                  CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
1372     ok(hres == S_OK, "Could not register screipt engine: %08x\n", hres);
1373
1374     return TRUE;
1375 }
1376
1377 static void gecko_installer_workaround(BOOL disable)
1378 {
1379     HKEY hkey;
1380     DWORD res;
1381
1382     static BOOL has_url = FALSE;
1383     static char url[2048];
1384
1385     if(!disable && !has_url)
1386         return;
1387
1388     res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey);
1389     if(res != ERROR_SUCCESS)
1390         return;
1391
1392     if(disable) {
1393         DWORD type, size = sizeof(url);
1394
1395         res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size);
1396         if(res == ERROR_SUCCESS && type == REG_SZ)
1397             has_url = TRUE;
1398
1399         RegDeleteValue(hkey, "GeckoUrl");
1400     }else {
1401         RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1);
1402     }
1403
1404     RegCloseKey(hkey);
1405 }
1406
1407 /* Check if Internet Explorer is configured to run in "Enhanced Security Configuration" (aka hardened mode) */
1408 /* Note: this code is duplicated in dlls/mshtml/tests/dom.c, dlls/mshtml/tests/script.c and dlls/urlmon/tests/sec_mgr.c */
1409 static BOOL is_ie_hardened(void)
1410 {
1411     HKEY zone_map;
1412     DWORD ie_harden, type, size;
1413
1414     ie_harden = 0;
1415     if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ZoneMap",
1416                     0, KEY_QUERY_VALUE, &zone_map) == ERROR_SUCCESS) {
1417         size = sizeof(DWORD);
1418         if (RegQueryValueEx(zone_map, "IEHarden", NULL, &type, (LPBYTE) &ie_harden, &size) != ERROR_SUCCESS ||
1419             type != REG_DWORD) {
1420             ie_harden = 0;
1421         }
1422     RegCloseKey(zone_map);
1423     }
1424
1425     return ie_harden != 0;
1426 }
1427
1428 START_TEST(script)
1429 {
1430     gecko_installer_workaround(TRUE);
1431     CoInitialize(NULL);
1432
1433     if(winetest_interactive || ! is_ie_hardened()) {
1434         if(register_script_engine()) {
1435             test_simple_script();
1436             init_registry(FALSE);
1437         }else {
1438             skip("Could not register TestScript engine\n");
1439         }
1440     }else {
1441         skip("IE running in Enhanced Security Configuration\n");
1442     }
1443
1444     CoUninitialize();
1445     gecko_installer_workaround(FALSE);
1446 }