gdiplus: Implement GdipGetEmHeight.
[wine] / dlls / mshtml / tests / 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 #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 "activscp.h"
32 #include "activdbg.h"
33 #include "objsafe.h"
34 #include "mshtmdid.h"
35
36 #define DEFINE_EXPECT(func) \
37     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
38
39 #define SET_EXPECT(func) \
40     do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
41
42 #define CHECK_EXPECT2(func) \
43     do { \
44         ok(expect_ ##func, "unexpected call " #func "\n"); \
45         called_ ## func = TRUE; \
46     }while(0)
47
48 #define CHECK_EXPECT(func) \
49     do { \
50         CHECK_EXPECT2(func); \
51         expect_ ## func = FALSE; \
52     }while(0)
53
54 #define CHECK_CALLED(func) \
55     do { \
56         ok(called_ ## func, "expected " #func "\n"); \
57         expect_ ## func = called_ ## func = FALSE; \
58     }while(0)
59
60 #define CHECK_NOT_CALLED(func) \
61     do { \
62         ok(!called_ ## func, "unexpected " #func "\n"); \
63         expect_ ## func = called_ ## func = FALSE; \
64     }while(0)
65
66 #define CLEAR_CALLED(func) \
67     expect_ ## func = called_ ## func = FALSE
68
69
70 DEFINE_EXPECT(CreateInstance);
71 DEFINE_EXPECT(GetInterfaceSafetyOptions);
72 DEFINE_EXPECT(SetInterfaceSafetyOptions);
73 DEFINE_EXPECT(InitNew);
74 DEFINE_EXPECT(Close);
75 DEFINE_EXPECT(SetProperty);
76 DEFINE_EXPECT(SetScriptSite);
77 DEFINE_EXPECT(GetScriptState);
78 DEFINE_EXPECT(SetScriptState_STARTED);
79 DEFINE_EXPECT(SetScriptState_CONNECTED);
80 DEFINE_EXPECT(SetScriptState_DISCONNECTED);
81 DEFINE_EXPECT(AddNamedItem);
82 DEFINE_EXPECT(ParseScriptText);
83 DEFINE_EXPECT(GetScriptDispatch);
84
85 #define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}"
86
87 static const GUID CLSID_TestScript =
88     {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}};
89
90 static IHTMLDocument2 *notif_doc;
91 static IDispatchEx *window_dispex;
92 static BOOL doc_complete;
93
94 static const char *debugstr_w(LPCWSTR str)
95 {
96     static char buf[1024];
97     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
98     return buf;
99 }
100
101 static const char *debugstr_guid(REFIID riid)
102 {
103     static char buf[50];
104
105     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
106             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
107             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
108             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
109
110     return buf;
111 }
112
113 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
114         REFIID riid, void**ppv)
115 {
116     if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
117         *ppv = iface;
118         return S_OK;
119     }
120
121     return E_NOINTERFACE;
122 }
123
124 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
125 {
126     return 2;
127 }
128
129 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
130 {
131     return 1;
132 }
133
134 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
135 {
136     if(dispID == DISPID_READYSTATE){
137         BSTR state;
138         HRESULT hres;
139
140         static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0};
141
142         hres = IHTMLDocument2_get_readyState(notif_doc, &state);
143         ok(hres == S_OK, "get_readyState failed: %08x\n", hres);
144
145         if(!lstrcmpW(state, completeW))
146             doc_complete = TRUE;
147
148         SysFreeString(state);
149     }
150
151     return S_OK;
152 }
153
154 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
155 {
156     ok(0, "unexpected call\n");
157     return E_NOTIMPL;
158 }
159
160 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
161     PropertyNotifySink_QueryInterface,
162     PropertyNotifySink_AddRef,
163     PropertyNotifySink_Release,
164     PropertyNotifySink_OnChanged,
165     PropertyNotifySink_OnRequestEdit
166 };
167
168 static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
169
170 static IHTMLDocument2 *create_document(void)
171 {
172     IHTMLDocument2 *doc;
173     HRESULT hres;
174
175     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
176             &IID_IHTMLDocument2, (void**)&doc);
177     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
178
179     return doc;
180 }
181
182 static IHTMLDocument2 *create_doc_with_string(const char *str)
183 {
184     IPersistStreamInit *init;
185     IStream *stream;
186     IHTMLDocument2 *doc;
187     HGLOBAL mem;
188     SIZE_T len;
189
190     notif_doc = doc = create_document();
191     if(!doc)
192         return NULL;
193
194     doc_complete = FALSE;
195     len = strlen(str);
196     mem = GlobalAlloc(0, len);
197     memcpy(mem, str, len);
198     CreateStreamOnHGlobal(mem, TRUE, &stream);
199
200     IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init);
201
202     IPersistStreamInit_Load(init, stream);
203     IPersistStreamInit_Release(init);
204     IStream_Release(stream);
205
206     return doc;
207 }
208
209 static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise)
210 {
211     IConnectionPointContainer *container;
212     IConnectionPoint *cp;
213     DWORD cookie;
214     HRESULT hres;
215
216     hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container);
217     ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
218
219     hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp);
220     IConnectionPointContainer_Release(container);
221     ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
222
223     hres = IConnectionPoint_Advise(cp, unk_advise, &cookie);
224     IConnectionPoint_Release(cp);
225     ok(hres == S_OK, "Advise failed: %08x\n", hres);
226 }
227
228 typedef void (*domtest_t)(IHTMLDocument2*);
229
230 static IHTMLDocument2 *create_and_load_doc(const char *str)
231 {
232     IHTMLDocument2 *doc;
233     IHTMLElement *body = NULL;
234     ULONG ref;
235     MSG msg;
236     HRESULT hres;
237
238     doc = create_doc_with_string(str);
239     do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
240
241     while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
242         TranslateMessage(&msg);
243         DispatchMessage(&msg);
244     }
245
246     hres = IHTMLDocument2_get_body(doc, &body);
247     ok(hres == S_OK, "get_body failed: %08x\n", hres);
248
249     if(!body) {
250         skip("Could not get document body. Assuming no Gecko installed.\n");
251         ref = IHTMLDocument2_Release(doc);
252         ok(!ref, "ref = %d\n", ref);
253         return NULL;
254     }
255
256     IHTMLElement_Release(body);
257     return doc;
258 }
259
260 static IActiveScriptSite *site;
261 static SCRIPTSTATE state;
262
263 static HRESULT WINAPI ObjectSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
264 {
265     *ppv = NULL;
266     ok(0, "unexpected call\n");
267     return E_NOINTERFACE;
268 }
269
270 static ULONG WINAPI ObjectSafety_AddRef(IObjectSafety *iface)
271 {
272     return 2;
273 }
274
275 static ULONG WINAPI ObjectSafety_Release(IObjectSafety *iface)
276 {
277     return 1;
278 }
279
280 static HRESULT WINAPI ObjectSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
281         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
282 {
283     CHECK_EXPECT(GetInterfaceSafetyOptions);
284
285     ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", debugstr_guid(riid));
286     ok(pdwSupportedOptions != NULL, "pdwSupportedOptions == NULL\n");
287     ok(pdwEnabledOptions != NULL, "pdwEnabledOptions == NULL\n");
288
289     *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER;
290     *pdwEnabledOptions = INTERFACE_USES_DISPEX;
291
292     return S_OK;
293 }
294
295 static HRESULT WINAPI ObjectSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
296         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
297 {
298     CHECK_EXPECT(SetInterfaceSafetyOptions);
299
300     ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", debugstr_guid(riid));
301
302     ok(dwOptionSetMask == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
303        "dwOptionSetMask=%x\n", dwOptionSetMask);
304     ok(dwEnabledOptions == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
305        "dwEnabledOptions=%x\n", dwOptionSetMask);
306
307     return S_OK;
308 }
309
310 static const IObjectSafetyVtbl ObjectSafetyVtbl = {
311     ObjectSafety_QueryInterface,
312     ObjectSafety_AddRef,
313     ObjectSafety_Release,
314     ObjectSafety_GetInterfaceSafetyOptions,
315     ObjectSafety_SetInterfaceSafetyOptions
316 };
317
318 static IObjectSafety ObjectSafety = { &ObjectSafetyVtbl };
319
320 static HRESULT WINAPI ActiveScriptProperty_QueryInterface(IActiveScriptProperty *iface, REFIID riid, void **ppv)
321 {
322     *ppv = NULL;
323     ok(0, "unexpected call\n");
324     return E_NOINTERFACE;
325 }
326
327 static ULONG WINAPI ActiveScriptProperty_AddRef(IActiveScriptProperty *iface)
328 {
329     return 2;
330 }
331
332 static ULONG WINAPI ActiveScriptProperty_Release(IActiveScriptProperty *iface)
333 {
334     return 1;
335 }
336
337 static HRESULT WINAPI ActiveScriptProperty_GetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
338         VARIANT *pvarIndex, VARIANT *pvarValue)
339 {
340     ok(0, "unexpected call\n");
341     return E_NOTIMPL;
342 }
343
344 static HRESULT WINAPI ActiveScriptProperty_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty,
345         VARIANT *pvarIndex, VARIANT *pvarValue)
346 {
347     CHECK_EXPECT(SetProperty);
348
349     ok(dwProperty == SCRIPTPROP_HACK_TRIDENTEVENTSINK, "unexpected property %d\n", dwProperty);
350     ok(!pvarIndex, "pvarIndex != NULL\n");
351     ok(pvarValue != NULL, "pvarValue == NULL\n");
352     ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue)=%d\n", V_VT(pvarValue));
353     ok(V_BOOL(pvarValue) == VARIANT_TRUE, "V_BOOL(pvarValue)=%x\n", V_BOOL(pvarValue));
354
355     return E_NOTIMPL;
356 }
357
358 static const IActiveScriptPropertyVtbl ActiveScriptPropertyVtbl = {
359     ActiveScriptProperty_QueryInterface,
360     ActiveScriptProperty_AddRef,
361     ActiveScriptProperty_Release,
362     ActiveScriptProperty_GetProperty,
363     ActiveScriptProperty_SetProperty
364 };
365
366 static IActiveScriptProperty ActiveScriptProperty = { &ActiveScriptPropertyVtbl };
367
368 static HRESULT WINAPI ActiveScriptParseProcedure_QueryInterface(IActiveScriptParseProcedure2 *iface, REFIID riid, void **ppv)
369 {
370     *ppv = NULL;
371     ok(0, "unexpected call\n");
372     return E_NOINTERFACE;
373 }
374
375 static ULONG WINAPI ActiveScriptParseProcedure_AddRef(IActiveScriptParseProcedure2 *iface)
376 {
377     return 2;
378 }
379
380 static ULONG WINAPI ActiveScriptParseProcedure_Release(IActiveScriptParseProcedure2 *iface)
381 {
382     return 1;
383 }
384
385 static HRESULT WINAPI ActiveScriptParseProcedure_ParseProcedureText(IActiveScriptParseProcedure2 *iface,
386         LPCOLESTR pstrCode, LPCOLESTR pstrFormalParams, LPCOLESTR pstrProcedureName,
387         LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter,
388         DWORD dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags, IDispatch **ppdisp)
389 {
390     ok(0, "unexpected call\n");
391     return E_NOTIMPL;
392 }
393
394 static const IActiveScriptParseProcedure2Vtbl ActiveScriptParseProcedureVtbl = {
395     ActiveScriptParseProcedure_QueryInterface,
396     ActiveScriptParseProcedure_AddRef,
397     ActiveScriptParseProcedure_Release,
398     ActiveScriptParseProcedure_ParseProcedureText
399 };
400
401 static IActiveScriptParseProcedure2 ActiveScriptParseProcedure = { &ActiveScriptParseProcedureVtbl };
402
403 static HRESULT WINAPI ActiveScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
404 {
405     *ppv = NULL;
406     ok(0, "unexpected call\n");
407     return E_NOINTERFACE;
408 }
409
410 static ULONG WINAPI ActiveScriptParse_AddRef(IActiveScriptParse *iface)
411 {
412     return 2;
413 }
414
415 static ULONG WINAPI ActiveScriptParse_Release(IActiveScriptParse *iface)
416 {
417     return 1;
418 }
419
420 static HRESULT WINAPI ActiveScriptParse_InitNew(IActiveScriptParse *iface)
421 {
422     CHECK_EXPECT(InitNew);
423     return S_OK;
424 }
425
426 static HRESULT WINAPI ActiveScriptParse_AddScriptlet(IActiveScriptParse *iface,
427         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
428         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
429         DWORD dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
430         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
431 {
432     ok(0, "unexpected call\n");
433     return E_NOTIMPL;
434 }
435
436 static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *iface,
437         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
438         LPCOLESTR pstrDelimiter, DWORD dwSourceContextCookie, ULONG ulStartingLine,
439         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
440 {
441     IDispatchEx *document;
442     IUnknown *unk;
443     VARIANT var;
444     DISPPARAMS dp;
445     EXCEPINFO ei;
446     DISPID id, named_arg = DISPID_PROPERTYPUT;
447     BSTR tmp;
448     HRESULT hres;
449
450     static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
451     static const WCHAR testW[] = {'t','e','s','t',0};
452
453     CHECK_EXPECT(ParseScriptText);
454
455     SET_EXPECT(GetScriptDispatch);
456
457     tmp = SysAllocString(documentW);
458     hres = IDispatchEx_GetDispID(window_dispex, tmp, fdexNameCaseSensitive, &id);
459     SysFreeString(tmp);
460     ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres);
461     ok(id == DISPID_IHTMLWINDOW2_DOCUMENT, "id=%x\n", id);
462
463     todo_wine CHECK_CALLED(GetScriptDispatch);
464
465     VariantInit(&var);
466     memset(&dp, 0, sizeof(dp));
467     memset(&ei, 0, sizeof(ei));
468
469     hres = IDispatchEx_InvokeEx(window_dispex, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL);
470     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
471     ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var));
472     ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(&var) == NULL\n");
473
474     hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IDispatchEx, (void**)&document);
475     VariantClear(&var);
476     ok(hres == S_OK, "Could not get DispatchEx: %08x\n", hres);
477
478     tmp = SysAllocString(testW);
479     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive, &id);
480     ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(document) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
481     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive | fdexNameImplicit, &id);
482     ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(document) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
483     SysFreeString(tmp);
484
485     id = 0;
486     tmp = SysAllocString(testW);
487     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive|fdexNameEnsure, &id);
488     SysFreeString(tmp);
489     ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres);
490     ok(id, "id == 0\n");
491
492     dp.cArgs = 1;
493     dp.rgvarg = &var;
494     dp.cNamedArgs = 1;
495     dp.rgdispidNamedArgs = &named_arg;
496     V_VT(&var) = VT_I4;
497     V_I4(&var) = 100;
498
499     hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYPUT, &dp, NULL, &ei, NULL);
500     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
501
502     tmp = SysAllocString(testW);
503     hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive, &id);
504     SysFreeString(tmp);
505     ok(hres == S_OK, "GetDispID(document) failed: %08x\n", hres);
506
507     VariantInit(&var);
508     memset(&dp, 0, sizeof(dp));
509     memset(&ei, 0, sizeof(ei));
510     hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL);
511     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
512     ok(V_VT(&var) == VT_I4, "V_VT(var)=%d\n", V_VT(&var));
513     ok(V_I4(&var) == 100, "V_I4(&var) == NULL\n");
514
515     IDispatchEx_Release(document);
516
517     unk = (void*)0xdeadbeef;
518     hres = IDispatchEx_GetNameSpaceParent(window_dispex, &unk);
519     ok(hres == S_OK, "GetNameSpaceParent failed: %08x\n", hres);
520     ok(!unk, "unk=%p, expected NULL\n", unk);
521
522     return S_OK;
523 }
524
525 static const IActiveScriptParseVtbl ActiveScriptParseVtbl = {
526     ActiveScriptParse_QueryInterface,
527     ActiveScriptParse_AddRef,
528     ActiveScriptParse_Release,
529     ActiveScriptParse_InitNew,
530     ActiveScriptParse_AddScriptlet,
531     ActiveScriptParse_ParseScriptText
532 };
533
534 static IActiveScriptParse ActiveScriptParse = { &ActiveScriptParseVtbl };
535
536 static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
537 {
538     *ppv = NULL;
539
540     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IActiveScript, riid)) {
541         *ppv = iface;
542         return S_OK;
543     }
544
545     if(IsEqualGUID(&IID_IActiveScriptParse, riid)) {
546         *ppv = &ActiveScriptParse;
547         return S_OK;
548     }
549
550     if(IsEqualGUID(&IID_IActiveScriptParseProcedure2, riid)) {
551         *ppv = &ActiveScriptParseProcedure;
552         return S_OK;
553     }
554
555     if(IsEqualGUID(&IID_IActiveScriptProperty, riid)) {
556         *ppv = &ActiveScriptProperty;
557         return S_OK;
558     }
559
560     if(IsEqualGUID(&IID_IObjectSafety, riid)) {
561         *ppv = &ObjectSafety;
562         return S_OK;
563     }
564
565     ok(0, "unexpected riid %s\n", debugstr_guid(riid));
566     return E_NOINTERFACE;
567 }
568
569 static ULONG WINAPI ActiveScript_AddRef(IActiveScript *iface)
570 {
571     return 2;
572 }
573
574 static ULONG WINAPI ActiveScript_Release(IActiveScript *iface)
575 {
576     return 1;
577 }
578
579 static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
580 {
581     IActiveScriptSiteInterruptPoll *poll;
582     IActiveScriptSiteDebug *debug;
583     LCID lcid;
584     HRESULT hres;
585
586     CHECK_EXPECT(SetScriptSite);
587
588     ok(pass != NULL, "pass == NULL\n");
589
590     hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteInterruptPoll, (void**)&poll);
591     ok(hres == S_OK, "Could not get IActiveScriptSiteInterruptPoll interface: %08x\n", hres);
592     if(FAILED(hres))
593         IActiveScriptSiteInterruptPoll_Release(poll);
594
595     hres = IActiveScriptSite_GetLCID(pass, &lcid);
596     ok(hres == S_OK, "GetLCID failed: %08x\n", hres);
597
598     hres = IActiveScriptSite_OnStateChange(pass, (state = SCRIPTSTATE_INITIALIZED));
599     ok(hres == S_OK, "OnStateChange failed: %08x\n", hres);
600
601     hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteDebug, (void**)&debug);
602     ok(hres == S_OK, "Could not get IActiveScriptSiteDebug interface: %08x\n", hres);
603     if(SUCCEEDED(hres))
604         IActiveScriptSiteDebug32_Release(debug);
605
606     site = pass;
607     IActiveScriptSite_AddRef(site);
608     return S_OK;
609 }
610
611 static HRESULT WINAPI ActiveScript_GetScriptSite(IActiveScript *iface, REFIID riid,
612                                             void **ppvObject)
613 {
614     ok(0, "unexpected call\n");
615     return E_NOTIMPL;
616 }
617
618 static HRESULT WINAPI ActiveScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
619 {
620     HRESULT hres;
621
622     switch(ss) {
623     case SCRIPTSTATE_STARTED:
624         CHECK_EXPECT(SetScriptState_STARTED);
625         break;
626     case SCRIPTSTATE_CONNECTED:
627         CHECK_EXPECT(SetScriptState_CONNECTED);
628         break;
629     case SCRIPTSTATE_DISCONNECTED:
630         CHECK_EXPECT(SetScriptState_DISCONNECTED);
631         break;
632     default:
633         ok(0, "unexpected state %d\n", ss);
634         return E_NOTIMPL;
635     }
636
637     hres = IActiveScriptSite_OnStateChange(site, (state = ss));
638     return S_OK;
639 }
640
641 static HRESULT WINAPI ActiveScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
642 {
643     CHECK_EXPECT(GetScriptState);
644
645     *pssState = state;
646     return S_OK;
647 }
648
649 static HRESULT WINAPI ActiveScript_Close(IActiveScript *iface)
650 {
651     CHECK_EXPECT(Close);
652     return E_NOTIMPL;
653 }
654
655 static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface,
656         LPCOLESTR pstrName, DWORD dwFlags)
657 {
658     IDispatch *disp;
659     IUnknown *unk = NULL, *unk2;
660     HRESULT hres;
661
662     static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
663
664     static const IID unknown_iid = {0x719C3050,0xF9D3,0x11CF,{0xA4,0x93,0x00,0x40,0x05,0x23,0xA8,0xA0}};
665
666     CHECK_EXPECT(AddNamedItem);
667
668     ok(!lstrcmpW(pstrName, windowW), "pstrName=%s\n", debugstr_w(pstrName));
669     ok(dwFlags == (SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS), "dwFlags=%x\n", dwFlags);
670
671     hres = IActiveScriptSite_GetItemInfo(site, windowW, SCRIPTINFO_IUNKNOWN, &unk, NULL);
672     ok(hres == S_OK, "GetItemInfo failed: %08x\n", hres);
673     ok(unk != NULL, "unk == NULL\n");
674
675     hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
676     ok(hres == S_OK, "Could not get IDispatch interface: %08x\n", hres);
677     if(SUCCEEDED(hres))
678         IDispatch_Release(disp);
679
680     hres = IUnknown_QueryInterface(unk, &unknown_iid, (void**)&unk2);
681     ok(hres == E_NOINTERFACE, "Got ?? interface: %p\n", unk2);
682     if(SUCCEEDED(hres))
683         IUnknown_Release(unk2);
684
685     hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&window_dispex);
686     ok(hres == S_OK, "Could not get IDispatchEx interface: %08x\n", hres);
687
688     IUnknown_Release(unk);
689     return S_OK;
690 }
691
692 static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
693                                          DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
694 {
695     ok(0, "unexpected call\n");
696     return E_NOTIMPL;
697 }
698
699 static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
700                                                 IDispatch **ppdisp)
701 {
702     CHECK_EXPECT(GetScriptDispatch);
703     return E_NOTIMPL;
704 }
705
706 static HRESULT WINAPI ActiveScript_GetCurrentScriptThreadID(IActiveScript *iface,
707                                                        SCRIPTTHREADID *pstridThread)
708 {
709     ok(0, "unexpected call\n");
710     return E_NOTIMPL;
711 }
712
713 static HRESULT WINAPI ActiveScript_GetScriptThreadID(IActiveScript *iface,
714                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
715 {
716     ok(0, "unexpected call\n");
717     return E_NOTIMPL;
718 }
719
720 static HRESULT WINAPI ActiveScript_GetScriptThreadState(IActiveScript *iface,
721         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
722 {
723     ok(0, "unexpected call\n");
724     return E_NOTIMPL;
725 }
726
727 static HRESULT WINAPI ActiveScript_InterruptScriptThread(IActiveScript *iface,
728         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
729 {
730     ok(0, "unexpected call\n");
731     return E_NOTIMPL;
732 }
733
734 static HRESULT WINAPI ActiveScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
735 {
736     ok(0, "unexpected call\n");
737     return E_NOTIMPL;
738 }
739
740 static const IActiveScriptVtbl ActiveScriptVtbl = {
741     ActiveScript_QueryInterface,
742     ActiveScript_AddRef,
743     ActiveScript_Release,
744     ActiveScript_SetScriptSite,
745     ActiveScript_GetScriptSite,
746     ActiveScript_SetScriptState,
747     ActiveScript_GetScriptState,
748     ActiveScript_Close,
749     ActiveScript_AddNamedItem,
750     ActiveScript_AddTypeLib,
751     ActiveScript_GetScriptDispatch,
752     ActiveScript_GetCurrentScriptThreadID,
753     ActiveScript_GetScriptThreadID,
754     ActiveScript_GetScriptThreadState,
755     ActiveScript_InterruptScriptThread,
756     ActiveScript_Clone
757 };
758
759 static IActiveScript ActiveScript = { &ActiveScriptVtbl };
760
761 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
762 {
763     *ppv = NULL;
764
765     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
766         *ppv = iface;
767         return S_OK;
768     }
769
770     if(IsEqualGUID(&IID_IMarshal, riid))
771         return E_NOINTERFACE;
772     if(IsEqualGUID(&CLSID_IdentityUnmarshal, riid))
773         return E_NOINTERFACE;
774
775     ok(0, "unexpected riid %s\n", debugstr_guid(riid));
776     return E_NOTIMPL;
777 }
778
779 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
780 {
781     return 2;
782 }
783
784 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
785 {
786     return 1;
787 }
788
789 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
790 {
791     CHECK_EXPECT(CreateInstance);
792
793     ok(!outer, "outer = %p\n", outer);
794     ok(IsEqualGUID(&IID_IActiveScript, riid), "unexpected riid %s\n", debugstr_guid(riid));
795     *ppv = &ActiveScript;
796     return S_OK;
797 }
798
799 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
800 {
801     ok(0, "unexpected call\n");
802     return S_OK;
803 }
804
805 static const IClassFactoryVtbl ClassFactoryVtbl = {
806     ClassFactory_QueryInterface,
807     ClassFactory_AddRef,
808     ClassFactory_Release,
809     ClassFactory_CreateInstance,
810     ClassFactory_LockServer
811 };
812
813 static IClassFactory script_cf = { &ClassFactoryVtbl };
814
815 static const char simple_script_str[] =
816     "<html><head></head><body>"
817     "<script language=\"TestScript\">simple script</script>"
818     "</body></html>";
819
820 static void test_simple_script(void)
821 {
822     IHTMLDocument2 *doc;
823
824     SET_EXPECT(CreateInstance);
825     SET_EXPECT(GetInterfaceSafetyOptions);
826     SET_EXPECT(SetInterfaceSafetyOptions);
827     SET_EXPECT(SetProperty);
828     SET_EXPECT(InitNew);
829     SET_EXPECT(SetScriptSite);
830     SET_EXPECT(GetScriptState);
831     SET_EXPECT(SetScriptState_STARTED);
832     SET_EXPECT(AddNamedItem);
833     SET_EXPECT(ParseScriptText);
834     SET_EXPECT(SetScriptState_CONNECTED);
835
836     doc = create_and_load_doc(simple_script_str);
837     if(!doc) return;
838
839     CHECK_CALLED(CreateInstance);
840     CHECK_CALLED(GetInterfaceSafetyOptions);
841     CHECK_CALLED(SetInterfaceSafetyOptions);
842     CHECK_CALLED(SetProperty);
843     CHECK_CALLED(InitNew);
844     CHECK_CALLED(SetScriptSite);
845     CHECK_CALLED(GetScriptState);
846     CHECK_CALLED(SetScriptState_STARTED);
847     CHECK_CALLED(AddNamedItem);
848     CHECK_CALLED(ParseScriptText);
849     CHECK_CALLED(SetScriptState_CONNECTED);
850
851     if(site)
852         IActiveScriptSite_Release(site);
853     if(window_dispex)
854         IDispatchEx_Release(window_dispex);
855
856     SET_EXPECT(SetScriptState_DISCONNECTED);
857     SET_EXPECT(Close);
858
859     IHTMLDocument2_Release(doc);
860
861     CHECK_CALLED(SetScriptState_DISCONNECTED);
862     CHECK_CALLED(Close);
863 }
864
865 static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
866 {
867     HKEY hkey;
868     DWORD res;
869
870     if(!init) {
871         RegDeleteKey(HKEY_CLASSES_ROOT, key_name);
872         return TRUE;
873     }
874
875     res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey);
876     if(res != ERROR_SUCCESS)
877         return FALSE;
878
879     if(def_value)
880         res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value));
881
882     RegCloseKey(hkey);
883
884     return res == ERROR_SUCCESS;
885 }
886
887 static BOOL init_registry(BOOL init)
888 {
889     return init_key("TestScript\\CLSID", TESTSCRIPT_CLSID, init)
890         && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A1-9847-11CF-8F20-00805F2CD064}",
891                     NULL, init)
892         && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A2-9847-11CF-8F20-00805F2CD064}",
893                     NULL, init);
894 }
895
896 static BOOL register_script_engine(void)
897 {
898     DWORD regid;
899     HRESULT hres;
900
901     if(!init_registry(TRUE)) {
902         init_registry(FALSE);
903         return FALSE;
904     }
905
906     hres = CoRegisterClassObject(&CLSID_TestScript, (IUnknown *)&script_cf,
907                                  CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
908     ok(hres == S_OK, "Could not register screipt engine: %08x\n", hres);
909
910     return TRUE;
911 }
912
913 static void gecko_installer_workaround(BOOL disable)
914 {
915     HKEY hkey;
916     DWORD res;
917
918     static BOOL has_url = FALSE;
919     static char url[2048];
920
921     if(!disable && !has_url)
922         return;
923
924     res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey);
925     if(res != ERROR_SUCCESS)
926         return;
927
928     if(disable) {
929         DWORD type, size = sizeof(url);
930
931         res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size);
932         if(res == ERROR_SUCCESS && type == REG_SZ)
933             has_url = TRUE;
934
935         RegDeleteValue(hkey, "GeckoUrl");
936     }else {
937         RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1);
938     }
939
940     RegCloseKey(hkey);
941 }
942
943 START_TEST(script)
944 {
945     gecko_installer_workaround(TRUE);
946     CoInitialize(NULL);
947
948     if(register_script_engine()) {
949         test_simple_script();
950         init_registry(FALSE);
951     }else {
952         skip("Could not register TestScript engine\n");
953     }
954
955     CoUninitialize();
956     gecko_installer_workaround(FALSE);
957 }