jscript: Added Object function invocation implementation.
[wine] / dlls / mshtml / tests / events.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 "mshtml.h"
30 #include "docobj.h"
31 #include "hlink.h"
32 #include "dispex.h"
33
34 #define DEFINE_EXPECT(func) \
35     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
36
37 #define SET_EXPECT(func) \
38     do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
39
40 #define CHECK_EXPECT2(func) \
41     do { \
42     trace(#func "\n"); \
43         ok(expect_ ##func, "unexpected call " #func "\n"); \
44         called_ ## func = TRUE; \
45     }while(0)
46
47 #define CHECK_EXPECT(func) \
48     do { \
49         CHECK_EXPECT2(func); \
50         expect_ ## func = FALSE; \
51     }while(0)
52
53 #define CHECK_CALLED(func) \
54     do { \
55         ok(called_ ## func, "expected " #func "\n"); \
56         expect_ ## func = called_ ## func = FALSE; \
57     }while(0)
58
59 DEFINE_EXPECT(document_onclick);
60 DEFINE_EXPECT(body_onclick);
61 DEFINE_EXPECT(div_onclick);
62 DEFINE_EXPECT(div_onclick_attached);
63 DEFINE_EXPECT(timeout);
64
65 static HWND container_hwnd = NULL;
66 static IHTMLWindow2 *window;
67 static IOleDocumentView *view;
68
69 typedef struct {
70     LONG x;
71     LONG y;
72     LONG offset_x;
73     LONG offset_y;
74 } xy_test_t;
75
76 static const xy_test_t no_xy = {-10,-10,-10,-10};
77 static const xy_test_t zero_xy = {0,0,0,0};
78
79 static const char empty_doc_str[] =
80     "<html></html>";
81
82 static const char click_doc_str[] =
83     "<html><body>"
84     "<div id=\"clickdiv\" style=\"text-align: center; background: red; font-size: 32\">click here</div>"
85     "</body></html>";
86
87 static const char *debugstr_w(LPCWSTR str)
88 {
89     static char buf[1024];
90     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
91     return buf;
92 }
93
94 static const char *debugstr_guid(REFIID riid)
95 {
96     static char buf[50];
97
98     sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
99             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
100             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
101             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
102
103     return buf;
104 }
105
106 static int strcmp_wa(LPCWSTR strw, const char *stra)
107 {
108     CHAR buf[512];
109     WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
110     return lstrcmpA(stra, buf);
111 }
112
113 static BSTR a2bstr(const char *str)
114 {
115     BSTR ret;
116     int len;
117
118     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
119     ret = SysAllocStringLen(NULL, len-1);
120     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
121
122     return ret;
123 }
124
125 static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2)
126 {
127     IUnknown *unk1, *unk2;
128
129     if(iface1 == iface2)
130         return TRUE;
131
132     IUnknown_QueryInterface(iface1, &IID_IUnknown, (void**)&unk1);
133     IUnknown_Release(unk1);
134     IUnknown_QueryInterface(iface1, &IID_IUnknown, (void**)&unk2);
135     IUnknown_Release(unk2);
136
137     return unk1 == unk2;
138 }
139
140 #define test_disp(u,id) _test_disp(__LINE__,u,id)
141 static void _test_disp(unsigned line, IUnknown *unk, const IID *diid)
142 {
143     IDispatchEx *dispex;
144     ITypeInfo *typeinfo;
145     UINT ticnt;
146     HRESULT hres;
147
148     hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex);
149     ok_(__FILE__,line) (hres == S_OK, "Could not get IDispatch: %08x\n", hres);
150     if(FAILED(hres))
151         return;
152
153     ticnt = 0xdeadbeef;
154     hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
155     ok_(__FILE__,line) (hres == S_OK, "GetTypeInfoCount failed: %08x\n", hres);
156     ok_(__FILE__,line) (ticnt == 1, "ticnt=%u\n", ticnt);
157
158     hres = IDispatchEx_GetTypeInfo(dispex, 0, 0, &typeinfo);
159     ok_(__FILE__,line) (hres == S_OK, "GetTypeInfo failed: %08x\n", hres);
160
161     if(SUCCEEDED(hres)) {
162         TYPEATTR *type_attr;
163
164         hres = ITypeInfo_GetTypeAttr(typeinfo, &type_attr);
165         ok_(__FILE__,line) (hres == S_OK, "GetTypeAttr failed: %08x\n", hres);
166         ok_(__FILE__,line) (IsEqualGUID(&type_attr->guid, diid), "unexpected guid %s\n",
167                             debugstr_guid(&type_attr->guid));
168
169         ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr);
170         ITypeInfo_Release(typeinfo);
171     }
172
173     IDispatchEx_Release(dispex);
174 }
175
176 #define get_doc3_iface(u) _get_doc3_iface(__LINE__,u)
177 static IHTMLDocument3 *_get_doc3_iface(unsigned line, IUnknown *unk)
178 {
179     IHTMLDocument3 *doc3;
180     HRESULT hres;
181
182     hres = IUnknown_QueryInterface(unk, &IID_IHTMLDocument3, (void**)&doc3);
183     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDocument3 iface: %08x\n", hres);
184
185     return doc3;
186 }
187
188 #define get_elem_iface(u) _get_elem_iface(__LINE__,u)
189 static IHTMLElement *_get_elem_iface(unsigned line, IUnknown *unk)
190 {
191     IHTMLElement *elem;
192     HRESULT hres;
193
194     hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement, (void**)&elem);
195     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement iface: %08x\n", hres);
196
197     return elem;
198 }
199
200 #define get_elem2_iface(u) _get_elem2_iface(__LINE__,u)
201 static IHTMLElement2 *_get_elem2_iface(unsigned line, IUnknown *unk)
202 {
203     IHTMLElement2 *elem2;
204     HRESULT hres;
205
206     hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement2, (void**)&elem2);
207     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement2 iface: %08x\n", hres);
208
209     return elem2;
210 }
211
212 #define doc_get_body(d) _doc_get_body(__LINE__,d)
213 static IHTMLElement *_doc_get_body(unsigned line, IHTMLDocument2 *doc)
214 {
215     IHTMLElement *body = NULL;
216     HRESULT hres;
217
218     hres = IHTMLDocument2_get_body(doc, &body);
219     ok_(__FILE__,line) (hres == S_OK, "get_body failed: %08x\n", hres);
220     ok_(__FILE__,line) (body != NULL, "body == NULL\n");
221
222     return body;
223 }
224
225 #define get_elem_id(d,i) _get_elem_id(__LINE__,d,i)
226 static IHTMLElement *_get_elem_id(unsigned line, IHTMLDocument2 *doc, const char *id)
227 {
228     IHTMLDocument3 *doc3 = _get_doc3_iface(line, (IUnknown*)doc);
229     IHTMLElement *elem;
230     BSTR str;
231     HRESULT hres;
232
233     str = a2bstr(id);
234     hres = IHTMLDocument3_getElementById(doc3, str, &elem);
235     SysFreeString(str);
236     IHTMLDocument3_Release(doc3);
237     ok_(__FILE__,line) (hres == S_OK, "getElementById failed: %08x\n", hres);
238
239     return elem;
240 }
241
242 #define test_elem_tag(u,n) _test_elem_tag(__LINE__,u,n)
243 static void _test_elem_tag(unsigned line, IUnknown *unk, const char *extag)
244 {
245     IHTMLElement *elem = _get_elem_iface(line, unk);
246     BSTR tag;
247     HRESULT hres;
248
249     hres = IHTMLElement_get_tagName(elem, &tag);
250     IHTMLElement_Release(elem);
251     ok_(__FILE__, line) (hres == S_OK, "get_tagName failed: %08x\n", hres);
252     ok_(__FILE__, line) (!strcmp_wa(tag, extag), "got tag: %s, expected %s\n", debugstr_w(tag), extag);
253
254     SysFreeString(tag);
255 }
256
257 #define get_event_obj() _get_event_obj(__LINE__)
258 static IHTMLEventObj *_get_event_obj(unsigned line)
259 {
260     IHTMLEventObj *event = NULL;
261     HRESULT hres;
262
263     hres = IHTMLWindow2_get_event(window, &event);
264     ok_(__FILE__,line) (hres == S_OK, "get_event failed: %08x\n", hres);
265     ok_(__FILE__,line) (event != NULL, "event = NULL\n");
266     _test_disp(line, (IUnknown*)event, &DIID_DispCEventObj);
267
268     return event;
269 }
270
271 #define test_event_args(a,b,c,d,e,f,g) _test_event_args(__LINE__,a,b,c,d,e,f,g)
272 static void _test_event_args(unsigned line, const IID *dispiid, DISPID id, WORD wFlags, DISPPARAMS *pdp,
273         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
274 {
275     ok_(__FILE__,line) (id == DISPID_VALUE, "id = %d\n", id);
276     ok_(__FILE__,line) (wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags);
277     ok_(__FILE__,line) (pdp != NULL, "pdp == NULL\n");
278     ok_(__FILE__,line) (pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs);
279     ok_(__FILE__,line) (pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs);
280     ok_(__FILE__,line) (pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %d\n",
281                         pdp->rgdispidNamedArgs[0]);
282     ok_(__FILE__,line) (V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg));
283     ok_(__FILE__,line) (pvarRes != NULL, "pvarRes == NULL\n");
284     ok_(__FILE__,line) (pei != NULL, "pei == NULL");
285     ok_(__FILE__,line) (!pspCaller, "pspCaller != NULL\n");
286
287     if(dispiid)
288         _test_disp(line, (IUnknown*)V_DISPATCH(pdp->rgvarg), dispiid);
289 }
290
291 #define test_attached_event_args(a,b,c,d,e) _test_attached_event_args(__LINE__,a,b,c,d,e)
292 static void _test_attached_event_args(unsigned line, DISPID id, WORD wFlags, DISPPARAMS *pdp,
293         VARIANT *pvarRes, EXCEPINFO *pei)
294 {
295     IHTMLEventObj *event;
296
297     ok(id == DISPID_VALUE, "id = %d\n", id);
298     ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags);
299     ok(pdp != NULL, "pDispParams == NULL\n");
300     ok(pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs);
301     ok(!pdp->cNamedArgs, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs);
302     ok(!pdp->rgdispidNamedArgs, "pdp->rgdispidNamedArgs = %p\n", pdp->rgdispidNamedArgs);
303     ok(pdp->rgvarg != NULL, "rgvarg = NULL\n");
304     ok(pvarRes != NULL, "pvarRes = NULL\n");
305     ok(pei != NULL, "pei = NULL\n");
306     ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pVarRes) = %d\n", V_VT(pvarRes));
307     ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(pdp->rgvarg) = %d\n", V_VT(pdp->rgvarg));
308     ok(V_DISPATCH(pdp->rgvarg) != NULL, "V_DISPATCH(pdp->rgvarg) = %p\n", V_DISPATCH(pdp->rgvarg));
309
310     event = _get_event_obj(line);
311     ok(iface_cmp((IUnknown*)event, (IUnknown*)V_DISPATCH(pdp->rgvarg)), "event != arg0\n");
312     IHTMLEventObj_Release(event);
313 }
314
315 #define test_event_src(t) _test_event_src(__LINE__,t)
316 static void _test_event_src(unsigned line, const char *src_tag)
317 {
318     IHTMLEventObj *event = _get_event_obj(line);
319     IHTMLElement *src_elem = NULL;
320     HRESULT hres;
321
322     hres = IHTMLEventObj_get_srcElement(event, &src_elem);
323     IHTMLEventObj_Release(event);
324     ok_(__FILE__,line) (hres == S_OK, "get_srcElement failed: %08x\n", hres);
325
326     if(src_tag) {
327         ok_(__FILE__,line) (src_elem != NULL, "src_elem = NULL\n");
328         _test_elem_tag(line, (IUnknown*)src_elem, src_tag);
329         IHTMLElement_Release(src_elem);
330     }else {
331         ok_(__FILE__,line) (!src_elem, "src_elem != NULL\n");
332     }
333 }
334
335 static void _test_event_altkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval)
336 {
337     VARIANT_BOOL b;
338     HRESULT hres;
339
340     hres = IHTMLEventObj_get_altKey(event, &b);
341     ok_(__FILE__,line)(hres == S_OK, "get_altKey failed: %08x\n", hres);
342     ok_(__FILE__,line)(b == exval, "altKey = %x, expected %x\n", b, exval);
343 }
344
345 static void _test_event_ctrlkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval)
346 {
347     VARIANT_BOOL b;
348     HRESULT hres;
349
350     hres = IHTMLEventObj_get_ctrlKey(event, &b);
351     ok_(__FILE__,line)(hres == S_OK, "get_ctrlKey failed: %08x\n", hres);
352     ok_(__FILE__,line)(b == exval, "ctrlKey = %x, expected %x\n", b, exval);
353 }
354
355 static void _test_event_shiftkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval)
356 {
357     VARIANT_BOOL b;
358     HRESULT hres;
359
360     hres = IHTMLEventObj_get_shiftKey(event, &b);
361     ok_(__FILE__,line)(hres == S_OK, "get_shiftKey failed: %08x\n", hres);
362     ok_(__FILE__,line)(b == exval, "shiftKey = %x, expected %x\n", b, exval);
363 }
364
365 static void _test_event_cancelbubble(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval)
366 {
367     VARIANT_BOOL b;
368     HRESULT hres;
369
370     hres = IHTMLEventObj_get_cancelBubble(event, &b);
371     ok_(__FILE__,line)(hres == S_OK, "get_cancelBubble failed: %08x\n", hres);
372     ok_(__FILE__,line)(b == exval, "cancelBubble = %x, expected %x\n", b, exval);
373 }
374
375 static void _test_event_fromelem(unsigned line, IHTMLEventObj *event, const char *from_tag)
376 {
377     IHTMLElement *elem;
378     HRESULT hres;
379
380     hres = IHTMLEventObj_get_fromElement(event, &elem);
381     ok_(__FILE__,line)(hres == S_OK, "get_fromElement failed: %08x\n", hres);
382     if(from_tag)
383         _test_elem_tag(line, (IUnknown*)elem, from_tag);
384     else
385         ok_(__FILE__,line)(elem == NULL, "fromElement != NULL\n");
386     if(elem)
387         IHTMLElement_Release(elem);
388 }
389
390 static void _test_event_toelem(unsigned line, IHTMLEventObj *event, const char *to_tag)
391 {
392     IHTMLElement *elem;
393     HRESULT hres;
394
395     hres = IHTMLEventObj_get_toElement(event, &elem);
396     ok_(__FILE__,line)(hres == S_OK, "get_toElement failed: %08x\n", hres);
397     if(to_tag)
398         _test_elem_tag(line, (IUnknown*)elem, to_tag);
399     else
400         ok_(__FILE__,line)(elem == NULL, "toElement != NULL\n");
401     if(elem)
402         IHTMLElement_Release(elem);
403 }
404
405 static void _test_event_keycode(unsigned line, IHTMLEventObj *event, LONG exl)
406 {
407     LONG l;
408     HRESULT hres;
409
410     hres = IHTMLEventObj_get_keyCode(event, &l);
411     ok_(__FILE__,line)(hres == S_OK, "get_keyCode failed: %08x\n", hres);
412     ok_(__FILE__,line)(l == exl, "keyCode = %x, expected %x\n", l, exl);
413 }
414
415 static void _test_event_button(unsigned line, IHTMLEventObj *event, LONG exl)
416 {
417     LONG l;
418     HRESULT hres;
419
420     hres = IHTMLEventObj_get_button(event, &l);
421     ok_(__FILE__,line)(hres == S_OK, "get_button failed: %08x\n", hres);
422     ok_(__FILE__,line)(l == exl, "button = %x, expected %x\n", l, exl);
423 }
424
425 static void _test_event_reason(unsigned line, IHTMLEventObj *event, LONG exl)
426 {
427     LONG l;
428     HRESULT hres;
429
430     hres = IHTMLEventObj_get_reason(event, &l);
431     ok_(__FILE__,line)(hres == S_OK, "get_reason failed: %08x\n", hres);
432     ok_(__FILE__,line)(l == exl, "reason = %x, expected %x\n", l, exl);
433 }
434
435 static void _test_event_x(unsigned line, IHTMLEventObj *event, LONG exl)
436 {
437     LONG l;
438     HRESULT hres;
439
440     hres = IHTMLEventObj_get_x(event, &l);
441     ok_(__FILE__,line)(hres == S_OK, "get_x failed: %08x\n", hres);
442     if(exl == -10) /* don't test the exact value */
443         todo_wine ok_(__FILE__,line)(l > 0, "x = %d\n", l);
444     else
445         ok_(__FILE__,line)(l == exl, "x = %d, expected %d\n", l, exl);
446 }
447
448 static void _test_event_y(unsigned line, IHTMLEventObj *event, LONG exl)
449 {
450     LONG l;
451     HRESULT hres;
452
453     hres = IHTMLEventObj_get_y(event, &l);
454     ok_(__FILE__,line)(hres == S_OK, "get_y failed: %08x\n", hres);
455     if(exl == -10) /* don't test the exact value */
456         todo_wine ok_(__FILE__,line)(l > 0, "y = %d\n", l);
457     else
458         ok_(__FILE__,line)(l == exl, "y = %d, expected %d\n", l, exl);
459 }
460
461 static void _test_event_clientx(unsigned line, IHTMLEventObj *event, LONG exl)
462 {
463     LONG l;
464     HRESULT hres;
465
466     hres = IHTMLEventObj_get_clientX(event, &l);
467     ok_(__FILE__,line)(hres == S_OK, "get_clientX failed: %08x\n", hres);
468     if(exl == -10) /* don't test the exact value */
469         ok_(__FILE__,line)(l > 0, "clientX = %d\n", l);
470     else
471         ok_(__FILE__,line)(l == exl, "clientX = %d, expected %d\n", l, exl);
472 }
473
474 static void _test_event_clienty(unsigned line, IHTMLEventObj *event, LONG exl)
475 {
476     LONG l;
477     HRESULT hres;
478
479     hres = IHTMLEventObj_get_clientY(event, &l);
480     ok_(__FILE__,line)(hres == S_OK, "get_clientY failed: %08x\n", hres);
481     if(exl == -10) /* don't test the exact value */
482         ok_(__FILE__,line)(l > 0, "clientY = %d\n", l);
483     else
484         ok_(__FILE__,line)(l == exl, "clientY = %d, expected %d\n", l, exl);
485 }
486
487 static void _test_event_offsetx(unsigned line, IHTMLEventObj *event, LONG exl)
488 {
489     LONG l;
490     HRESULT hres;
491
492     hres = IHTMLEventObj_get_offsetX(event, &l);
493     ok_(__FILE__,line)(hres == S_OK, "get_offsetX failed: %08x\n", hres);
494     if(exl == -10) /* don't test the exact value */
495         todo_wine ok_(__FILE__,line)(l > 0, "offsetX = %d\n", l);
496     else
497         ok_(__FILE__,line)(l == exl, "offsetX = %d, expected %d\n", l, exl);
498 }
499
500 static void _test_event_offsety(unsigned line, IHTMLEventObj *event, LONG exl)
501 {
502     LONG l;
503     HRESULT hres;
504
505     hres = IHTMLEventObj_get_offsetY(event, &l);
506     ok_(__FILE__,line)(hres == S_OK, "get_offsetY failed: %08x\n", hres);
507     if(exl == -10) /* don't test the exact value */
508         todo_wine ok_(__FILE__,line)(l > 0, "offsetY = %d\n", l);
509     else
510         ok_(__FILE__,line)(l == exl, "offsetY = %d, expected %d\n", l, exl);
511 }
512
513 static void _test_event_screenx(unsigned line, IHTMLEventObj *event, LONG exl)
514 {
515     LONG l;
516     HRESULT hres;
517
518     hres = IHTMLEventObj_get_screenX(event, &l);
519     ok_(__FILE__,line)(hres == S_OK, "get_screenX failed: %08x\n", hres);
520     if(exl == -10) /* don't test the exact value */
521         ok_(__FILE__,line)(l > 0, "screenX = %d\n", l);
522     else
523         ok_(__FILE__,line)(l == exl, "screenX = %d, expected %d\n", l, exl);
524 }
525
526 static void _test_event_screeny(unsigned line, IHTMLEventObj *event, LONG exl)
527 {
528     LONG l;
529     HRESULT hres;
530
531     hres = IHTMLEventObj_get_screenY(event, &l);
532     ok_(__FILE__,line)(hres == S_OK, "get_screenY failed: %08x\n", hres);
533     if(exl == -10) /* don't test the exact value */
534         ok_(__FILE__,line)(l > 0, "screenY = %d\n", l);
535     else
536         ok_(__FILE__,line)(l == exl, "screenY = %d, expected %d\n", l, exl);
537 }
538
539 static void _test_event_type(unsigned line, IHTMLEventObj *event, const char *exstr)
540 {
541     BSTR str;
542     HRESULT hres;
543
544     hres = IHTMLEventObj_get_type(event, &str);
545     ok_(__FILE__,line)(hres == S_OK, "get_type failed: %08x\n", hres);
546     ok_(__FILE__,line)(!strcmp_wa(str, exstr), "type = %s, expected %s\n", wine_dbgstr_w(str), exstr);
547 }
548
549 static void _test_event_qualifier(unsigned line, IHTMLEventObj *event, const char *exstr)
550 {
551     BSTR str;
552     HRESULT hres;
553
554     hres = IHTMLEventObj_get_qualifier(event, &str);
555     ok_(__FILE__,line)(hres == S_OK, "get_qualifier failed: %08x\n", hres);
556     if(exstr)
557         ok_(__FILE__,line)(!strcmp_wa(str, exstr), "qualifier = %s, expected %s\n", wine_dbgstr_w(str), exstr);
558     else
559         ok_(__FILE__,line)(!str, "qualifier != NULL\n");
560 }
561
562 static void _test_event_srcfilter(unsigned line, IHTMLEventObj *event)
563 {
564     IDispatch *disp;
565     HRESULT hres;
566
567     hres = IHTMLEventObj_get_srcFilter(event, &disp);
568     ok_(__FILE__,line)(hres == S_OK, "get_srcFilter failed: %08x\n", hres);
569     ok_(__FILE__,line)(!disp, "srcFilter != NULL\n");
570 }
571
572 #define test_event_obj(t,x) _test_event_obj(__LINE__,t,x)
573 static void _test_event_obj(unsigned line, const char *type, const xy_test_t *xy)
574 {
575     IHTMLEventObj *event = _get_event_obj(line);
576     VARIANT v;
577     HRESULT hres;
578
579     _test_event_altkey(line, event, VARIANT_FALSE);
580     _test_event_ctrlkey(line, event, VARIANT_FALSE);
581     _test_event_shiftkey(line, event, VARIANT_FALSE);
582     _test_event_cancelbubble(line, event, VARIANT_FALSE);
583     _test_event_fromelem(line, event, NULL);
584     _test_event_toelem(line, event, NULL);
585     _test_event_keycode(line, event, 0);
586     _test_event_button(line, event, 0);
587     _test_event_type(line, event, type);
588     _test_event_qualifier(line, event, NULL);
589     _test_event_reason(line, event, 0);
590     _test_event_srcfilter(line, event);
591     _test_event_x(line, event, xy->x);
592     _test_event_y(line, event, xy->y);
593     _test_event_clientx(line, event, -10);
594     _test_event_clienty(line, event, -10);
595     _test_event_offsetx(line, event, xy->offset_x);
596     _test_event_offsety(line, event, xy->offset_y);
597     _test_event_screenx(line, event, -10);
598     _test_event_screeny(line, event, -10);
599
600     hres = IHTMLEventObj_get_returnValue(event, &v);
601     ok_(__FILE__,line)(hres == S_OK, "get_returnValue failed: %08x\n", hres);
602     ok_(__FILE__,line)(V_VT(&v) == VT_EMPTY, "V_VT(returnValue) = %d\n", V_VT(&v));
603
604     IHTMLEventObj_Release(event);
605 }
606
607 #define elem_attach_event(a,b,c) _elem_attach_event(__LINE__,a,b,c)
608 static void _elem_attach_event(unsigned line, IUnknown *unk, const char *namea, IDispatch *disp)
609 {
610     IHTMLElement2 *elem = _get_elem2_iface(line, unk);
611     VARIANT_BOOL res;
612     BSTR name;
613     HRESULT hres;
614
615     name = a2bstr(namea);
616     hres = IHTMLElement2_attachEvent(elem, name, disp, &res);
617     IHTMLElement2_Release(elem);
618     SysFreeString(name);
619     ok_(__FILE__,line)(hres == S_OK, "attachEvent failed: %08x\n", hres);
620     ok_(__FILE__,line)(res == VARIANT_TRUE, "attachEvent returned %x\n", res);
621 }
622
623 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
624 {
625     *ppv = NULL;
626
627     if(IsEqualGUID(riid, &IID_IUnknown)
628        || IsEqualGUID(riid, &IID_IDispatch)
629        || IsEqualGUID(riid, &IID_IDispatchEx))
630         *ppv = iface;
631     else {
632         ok(0, "unexpected riid %s\n", debugstr_guid(riid));
633         return E_NOINTERFACE;
634     }
635
636     return S_OK;
637 }
638
639 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
640 {
641     return 2;
642 }
643
644 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
645 {
646     return 1;
647 }
648
649 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
650 {
651     ok(0, "unexpected call\n");
652     return E_NOTIMPL;
653 }
654
655 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
656                                               LCID lcid, ITypeInfo **ppTInfo)
657 {
658     ok(0, "unexpected call\n");
659     return E_NOTIMPL;
660 }
661
662 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
663                                                 LPOLESTR *rgszNames, UINT cNames,
664                                                 LCID lcid, DISPID *rgDispId)
665 {
666     ok(0, "unexpected call\n");
667     return E_NOTIMPL;
668 }
669
670 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
671                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
672                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
673 {
674     ok(0, "unexpected call\n");
675     return E_NOTIMPL;
676 }
677
678 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
679 {
680     ok(0, "unexpected call\n");
681     return E_NOTIMPL;
682 }
683
684 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
685         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
686 {
687     ok(0, "unexpected call\n");
688     return E_NOTIMPL;
689 }
690
691 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
692 {
693     ok(0, "unexpected call %s %x\n", debugstr_w(bstrName), grfdex);
694     return E_NOTIMPL;
695 }
696
697 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
698 {
699     ok(0, "unexpected call\n");
700     return E_NOTIMPL;
701 }
702
703 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
704 {
705     ok(0, "unexpected call\n");
706     return E_NOTIMPL;
707 }
708
709 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
710 {
711     ok(0, "unexpected call\n");
712     return E_NOTIMPL;
713 }
714
715 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
716 {
717     ok(0, "unexpected call\n");
718     return E_NOTIMPL;
719 }
720
721 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
722 {
723     ok(0, "unexpected call\n");
724     return E_NOTIMPL;
725 }
726
727 #define EVENT_HANDLER_FUNC_OBJ(event) \
728     static IDispatchExVtbl event ## FuncVtbl = { \
729         DispatchEx_QueryInterface, \
730         DispatchEx_AddRef, \
731         DispatchEx_Release, \
732         DispatchEx_GetTypeInfoCount, \
733         DispatchEx_GetTypeInfo, \
734         DispatchEx_GetIDsOfNames, \
735         DispatchEx_Invoke, \
736         DispatchEx_GetDispID, \
737         event, \
738         DispatchEx_DeleteMemberByName, \
739         DispatchEx_DeleteMemberByDispID, \
740         DispatchEx_GetMemberProperties, \
741         DispatchEx_GetMemberName, \
742         DispatchEx_GetNextDispID, \
743         DispatchEx_GetNameSpaceParent \
744     }; \
745     static IDispatchEx event ## _obj = { &event ## FuncVtbl };
746
747 static HRESULT WINAPI document_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
748         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
749 {
750     IHTMLDocument3 *doc3;
751     CHECK_EXPECT(document_onclick);
752     test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller);
753     doc3 = get_doc3_iface((IUnknown*)V_DISPATCH(pdp->rgvarg));
754     IHTMLDocument3_Release(doc3);
755     test_event_src("DIV");
756     test_event_obj("click", &no_xy);
757     return S_OK;
758 }
759
760 EVENT_HANDLER_FUNC_OBJ(document_onclick);
761
762 static HRESULT WINAPI div_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
763         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
764 {
765     CHECK_EXPECT(div_onclick);
766     test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller);
767     test_event_src("DIV");
768     return S_OK;
769 }
770
771 EVENT_HANDLER_FUNC_OBJ(div_onclick);
772
773 static HRESULT WINAPI div_onclick_attached(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
774         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
775 {
776     CHECK_EXPECT(div_onclick_attached);
777
778     test_attached_event_args(id, wFlags, pdp, pvarRes, pei);
779     test_event_src("DIV");
780     return S_OK;
781 }
782
783 EVENT_HANDLER_FUNC_OBJ(div_onclick_attached);
784
785 static HRESULT WINAPI body_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
786         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
787 {
788     CHECK_EXPECT(body_onclick);
789     test_event_args(&DIID_DispHTMLBody, id, wFlags, pdp, pvarRes, pei, pspCaller);
790     test_event_src("DIV");
791     return S_OK;
792 }
793
794 EVENT_HANDLER_FUNC_OBJ(body_onclick);
795
796 static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
797         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
798 {
799     ok(0, "unexpected call\n");
800     return S_OK;
801 }
802
803 EVENT_HANDLER_FUNC_OBJ(nocall);
804
805 static HRESULT WINAPI timeoutFunc_Invoke(IDispatchEx *iface, DISPID dispIdMember,
806                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
807                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
808 {
809     CHECK_EXPECT(timeout);
810
811     ok(dispIdMember == DISPID_VALUE, "dispIdMember = %d\n", dispIdMember);
812     ok(IsEqualGUID(&IID_NULL, riid), "riid = %s\n", debugstr_guid(riid));
813     ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags);
814     ok(!lcid, "lcid = %x\n", lcid);
815     ok(pDispParams != NULL, "pDispParams == NULL\n");
816     ok(!pDispParams->cArgs, "pdp->cArgs = %d\n", pDispParams->cArgs);
817     ok(!pDispParams->cNamedArgs, "pdp->cNamedArgs = %d\n", pDispParams->cNamedArgs);
818     ok(!pDispParams->rgdispidNamedArgs, "pdp->rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs);
819     ok(!pDispParams->rgvarg, "rgvarg = %p\n", pDispParams->rgvarg);
820     ok(pVarResult != NULL, "pVarResult = NULL\n");
821     ok(pExcepInfo != NULL, "pExcepInfo = NULL\n");
822     ok(!puArgErr, "puArgErr = %p\n", puArgErr);
823     ok(V_VT(pVarResult) == VT_EMPTY, "V_VT(pVarResult) = %d\n", V_VT(pVarResult));
824
825     return S_OK;
826 }
827
828 static IDispatchExVtbl timeoutFuncVtbl = {
829     DispatchEx_QueryInterface,
830     DispatchEx_AddRef,
831     DispatchEx_Release,
832     DispatchEx_GetTypeInfoCount,
833     DispatchEx_GetTypeInfo,
834     DispatchEx_GetIDsOfNames,
835     timeoutFunc_Invoke,
836     DispatchEx_GetDispID,
837     DispatchEx_InvokeEx,
838     DispatchEx_DeleteMemberByName,
839     DispatchEx_DeleteMemberByDispID,
840     DispatchEx_GetMemberProperties,
841     DispatchEx_GetMemberName,
842     DispatchEx_GetNextDispID,
843     DispatchEx_GetNameSpaceParent
844 };
845
846 static IDispatchEx timeoutFunc = { &timeoutFuncVtbl };
847
848 static void pump_msgs(BOOL *b)
849 {
850     MSG msg;
851     while(!*b && GetMessage(&msg, NULL, 0, 0)) {
852         TranslateMessage(&msg);
853         DispatchMessage(&msg);
854     }
855 }
856
857 static void test_onclick(IHTMLDocument2 *doc)
858 {
859     IHTMLElement *div, *body;
860     VARIANT v;
861     HRESULT hres;
862
863     div = get_elem_id(doc, "clickdiv");
864
865     elem_attach_event((IUnknown*)div, "abcde", (IDispatch*)&nocall_obj);
866     elem_attach_event((IUnknown*)div, "onclick", (IDispatch*)&div_onclick_attached_obj);
867
868     V_VT(&v) = VT_EMPTY;
869     hres = IHTMLElement_get_onclick(div, &v);
870     ok(hres == S_OK, "get_onclick failed: %08x\n", hres);
871     ok(V_VT(&v) == VT_NULL, "V_VT(onclick) = %d\n", V_VT(&v));
872
873     V_VT(&v) = VT_DISPATCH;
874     V_DISPATCH(&v) = (IDispatch*)&div_onclick_obj;
875     hres = IHTMLElement_put_onclick(div, v);
876     ok(hres == S_OK, "put_onclick failed: %08x\n", hres);
877
878     V_VT(&v) = VT_EMPTY;
879     hres = IHTMLElement_get_onclick(div, &v);
880     ok(hres == S_OK, "get_onclick failed: %08x\n", hres);
881     ok(V_VT(&v) == VT_DISPATCH, "V_VT(onclick) = %d\n", V_VT(&v));
882     ok(V_DISPATCH(&v) == (IDispatch*)&div_onclick_obj, "V_DISPATCH(onclick) != onclickFunc\n");
883     VariantClear(&v);
884
885     V_VT(&v) = VT_EMPTY;
886     hres = IHTMLDocument2_get_onclick(doc, &v);
887     ok(hres == S_OK, "get_onclick failed: %08x\n", hres);
888     ok(V_VT(&v) == VT_NULL, "V_VT(onclick) = %d\n", V_VT(&v));
889
890     V_VT(&v) = VT_DISPATCH;
891     V_DISPATCH(&v) = (IDispatch*)&document_onclick_obj;
892     hres = IHTMLDocument2_put_onclick(doc, v);
893     ok(hres == S_OK, "put_onclick failed: %08x\n", hres);
894
895     V_VT(&v) = VT_EMPTY;
896     hres = IHTMLDocument2_get_onclick(doc, &v);
897     ok(hres == S_OK, "get_onclick failed: %08x\n", hres);
898     ok(V_VT(&v) == VT_DISPATCH, "V_VT(onclick) = %d\n", V_VT(&v));
899     ok(V_DISPATCH(&v) == (IDispatch*)&document_onclick_obj, "V_DISPATCH(onclick) != onclickFunc\n");
900     VariantClear(&v);
901
902     body = doc_get_body(doc);
903
904     V_VT(&v) = VT_DISPATCH;
905     V_DISPATCH(&v) = (IDispatch*)&body_onclick_obj;
906     hres = IHTMLElement_put_onclick(body, v);
907     ok(hres == S_OK, "put_onclick failed: %08x\n", hres);
908
909     if(winetest_interactive) {
910         SET_EXPECT(div_onclick);
911         SET_EXPECT(div_onclick_attached);
912         SET_EXPECT(body_onclick);
913         SET_EXPECT(document_onclick);
914         pump_msgs(&called_document_onclick);
915         CHECK_CALLED(div_onclick);
916         CHECK_CALLED(div_onclick_attached);
917         CHECK_CALLED(body_onclick);
918         CHECK_CALLED(document_onclick);
919     }
920
921     IHTMLElement_Release(div);
922     IHTMLElement_Release(body);
923 }
924
925 static void test_timeout(IHTMLDocument2 *doc)
926 {
927     IHTMLWindow3 *win3;
928     VARIANT expr, var;
929     LONG id;
930     HRESULT hres;
931
932     hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow3, (void**)&win3);
933     ok(hres == S_OK, "Could not get IHTMLWindow3 iface: %08x\n", hres);
934
935     V_VT(&expr) = VT_DISPATCH;
936     V_DISPATCH(&expr) = (IDispatch*)&timeoutFunc;
937     V_VT(&var) = VT_EMPTY;
938     id = 0;
939     hres = IHTMLWindow3_setTimeout(win3, &expr, 0, &var, &id);
940     ok(hres == S_OK, "setTimeout failed: %08x\n", hres);
941     ok(id, "id = 0\n");
942
943     SET_EXPECT(timeout);
944     pump_msgs(&called_timeout);
945     CHECK_CALLED(timeout);
946
947     V_VT(&expr) = VT_DISPATCH;
948     V_DISPATCH(&expr) = (IDispatch*)&timeoutFunc;
949     V_VT(&var) = VT_EMPTY;
950     id = 0;
951     hres = IHTMLWindow3_setTimeout(win3, &expr, 0, &var, &id);
952     ok(hres == S_OK, "setTimeout failed: %08x\n", hres);
953     ok(id, "id = 0\n");
954
955     hres = IHTMLWindow2_clearTimeout(window, id);
956     ok(hres == S_OK, "clearTimeout failed: %08x\n", hres);
957
958     IHTMLWindow3_Release(win3);
959 }
960
961 static HRESULT QueryInterface(REFIID,void**);
962
963 static HRESULT WINAPI InPlaceFrame_QueryInterface(IOleInPlaceFrame *iface, REFIID riid, void **ppv)
964 {
965     return E_NOINTERFACE;
966 }
967
968 static ULONG WINAPI InPlaceFrame_AddRef(IOleInPlaceFrame *iface)
969 {
970     return 2;
971 }
972
973 static ULONG WINAPI InPlaceFrame_Release(IOleInPlaceFrame *iface)
974 {
975     return 1;
976 }
977
978 static HRESULT WINAPI InPlaceFrame_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd)
979 {
980     return E_NOTIMPL;
981 }
982
983 static HRESULT WINAPI InPlaceFrame_ContextSensitiveHelp(IOleInPlaceFrame *iface, BOOL fEnterMode)
984 {
985     return E_NOTIMPL;
986 }
987
988 static HRESULT WINAPI InPlaceFrame_GetBorder(IOleInPlaceFrame *iface, LPRECT lprectBorder)
989 {
990     return E_NOTIMPL;
991 }
992
993 static HRESULT WINAPI InPlaceFrame_RequestBorderSpace(IOleInPlaceFrame *iface,
994         LPCBORDERWIDTHS pborderwidths)
995 {
996     return E_NOTIMPL;
997 }
998
999 static HRESULT WINAPI InPlaceFrame_SetBorderSpace(IOleInPlaceFrame *iface,
1000         LPCBORDERWIDTHS pborderwidths)
1001 {
1002     return S_OK;
1003 }
1004
1005 static HRESULT WINAPI InPlaceUIWindow_SetActiveObject(IOleInPlaceFrame *iface,
1006         IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
1007 {
1008     return S_OK;
1009 }
1010
1011 static HRESULT WINAPI InPlaceFrame_SetActiveObject(IOleInPlaceFrame *iface,
1012         IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
1013 {
1014     return S_OK;
1015 }
1016
1017 static HRESULT WINAPI InPlaceFrame_InsertMenus(IOleInPlaceFrame *iface, HMENU hmenuShared,
1018         LPOLEMENUGROUPWIDTHS lpMenuWidths)
1019 {
1020     return E_NOTIMPL;
1021 }
1022
1023 static HRESULT WINAPI InPlaceFrame_SetMenu(IOleInPlaceFrame *iface, HMENU hmenuShared,
1024         HOLEMENU holemenu, HWND hwndActiveObject)
1025 {
1026     ok(0, "unexpected call\n");
1027     return E_NOTIMPL;
1028 }
1029
1030 static HRESULT WINAPI InPlaceFrame_RemoveMenus(IOleInPlaceFrame *iface, HMENU hmenuShared)
1031 {
1032     ok(0, "unexpected call\n");
1033     return E_NOTIMPL;
1034 }
1035
1036 static HRESULT WINAPI InPlaceFrame_SetStatusText(IOleInPlaceFrame *iface, LPCOLESTR pszStatusText)
1037 {
1038     return S_OK;
1039 }
1040
1041 static HRESULT WINAPI InPlaceFrame_EnableModeless(IOleInPlaceFrame *iface, BOOL fEnable)
1042 {
1043     return E_NOTIMPL;
1044 }
1045
1046 static HRESULT WINAPI InPlaceFrame_TranslateAccelerator(IOleInPlaceFrame *iface, LPMSG lpmsg, WORD wID)
1047 {
1048     ok(0, "unexpected call\n");
1049     return E_NOTIMPL;
1050 }
1051
1052 static const IOleInPlaceFrameVtbl InPlaceFrameVtbl = {
1053     InPlaceFrame_QueryInterface,
1054     InPlaceFrame_AddRef,
1055     InPlaceFrame_Release,
1056     InPlaceFrame_GetWindow,
1057     InPlaceFrame_ContextSensitiveHelp,
1058     InPlaceFrame_GetBorder,
1059     InPlaceFrame_RequestBorderSpace,
1060     InPlaceFrame_SetBorderSpace,
1061     InPlaceFrame_SetActiveObject,
1062     InPlaceFrame_InsertMenus,
1063     InPlaceFrame_SetMenu,
1064     InPlaceFrame_RemoveMenus,
1065     InPlaceFrame_SetStatusText,
1066     InPlaceFrame_EnableModeless,
1067     InPlaceFrame_TranslateAccelerator
1068 };
1069
1070 static IOleInPlaceFrame InPlaceFrame = { &InPlaceFrameVtbl };
1071
1072 static const IOleInPlaceFrameVtbl InPlaceUIWindowVtbl = {
1073     InPlaceFrame_QueryInterface,
1074     InPlaceFrame_AddRef,
1075     InPlaceFrame_Release,
1076     InPlaceFrame_GetWindow,
1077     InPlaceFrame_ContextSensitiveHelp,
1078     InPlaceFrame_GetBorder,
1079     InPlaceFrame_RequestBorderSpace,
1080     InPlaceFrame_SetBorderSpace,
1081     InPlaceUIWindow_SetActiveObject,
1082 };
1083
1084 static IOleInPlaceFrame InPlaceUIWindow = { &InPlaceUIWindowVtbl };
1085
1086 static HRESULT WINAPI InPlaceSite_QueryInterface(IOleInPlaceSite *iface, REFIID riid, void **ppv)
1087 {
1088     return QueryInterface(riid, ppv);
1089 }
1090
1091 static ULONG WINAPI InPlaceSite_AddRef(IOleInPlaceSite *iface)
1092 {
1093     return 2;
1094 }
1095
1096 static ULONG WINAPI InPlaceSite_Release(IOleInPlaceSite *iface)
1097 {
1098     return 1;
1099 }
1100
1101 static HRESULT WINAPI InPlaceSite_GetWindow(IOleInPlaceSite *iface, HWND *phwnd)
1102 {
1103     *phwnd = container_hwnd;
1104     return S_OK;
1105 }
1106
1107 static HRESULT WINAPI InPlaceSite_ContextSensitiveHelp(IOleInPlaceSite *iface, BOOL fEnterMode)
1108 {
1109     ok(0, "unexpected call\n");
1110     return E_NOTIMPL;
1111 }
1112
1113 static HRESULT WINAPI InPlaceSite_CanInPlaceActivate(IOleInPlaceSite *iface)
1114 {
1115     return S_OK;
1116 }
1117
1118 static HRESULT WINAPI InPlaceSite_OnInPlaceActivate(IOleInPlaceSite *iface)
1119 {
1120     return S_OK;
1121 }
1122
1123 static HRESULT WINAPI InPlaceSite_OnUIActivate(IOleInPlaceSite *iface)
1124 {
1125     return S_OK;
1126 }
1127
1128 static HRESULT WINAPI InPlaceSite_GetWindowContext(IOleInPlaceSite *iface,
1129         IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect,
1130         LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
1131 {
1132     static const RECT rect = {0,0,300,300};
1133
1134     *ppFrame = &InPlaceFrame;
1135     *ppDoc = (IOleInPlaceUIWindow*)&InPlaceUIWindow;
1136     *lprcPosRect = rect;
1137     *lprcClipRect = rect;
1138
1139     lpFrameInfo->cb = sizeof(*lpFrameInfo);
1140     lpFrameInfo->fMDIApp = FALSE;
1141     lpFrameInfo->hwndFrame = container_hwnd;
1142     lpFrameInfo->haccel = NULL;
1143     lpFrameInfo->cAccelEntries = 0;
1144
1145     return S_OK;
1146 }
1147
1148 static HRESULT WINAPI InPlaceSite_Scroll(IOleInPlaceSite *iface, SIZE scrollExtant)
1149 {
1150     return E_NOTIMPL;
1151 }
1152
1153 static HRESULT WINAPI InPlaceSite_OnUIDeactivate(IOleInPlaceSite *iface, BOOL fUndoable)
1154 {
1155     return S_OK;
1156 }
1157
1158 static HRESULT WINAPI InPlaceSite_OnInPlaceDeactivate(IOleInPlaceSite *iface)
1159 {
1160     return S_OK;
1161 }
1162
1163 static HRESULT WINAPI InPlaceSite_DiscardUndoState(IOleInPlaceSite *iface)
1164 {
1165     return E_NOTIMPL;
1166 }
1167
1168 static HRESULT WINAPI InPlaceSite_DeactivateAndUndo(IOleInPlaceSite *iface)
1169 {
1170     return E_NOTIMPL;
1171 }
1172
1173 static HRESULT WINAPI InPlaceSite_OnPosRectChange(IOleInPlaceSite *iface, LPCRECT lprcPosRect)
1174 {
1175     return E_NOTIMPL;
1176 }
1177
1178 static const IOleInPlaceSiteVtbl InPlaceSiteVtbl = {
1179     InPlaceSite_QueryInterface,
1180     InPlaceSite_AddRef,
1181     InPlaceSite_Release,
1182     InPlaceSite_GetWindow,
1183     InPlaceSite_ContextSensitiveHelp,
1184     InPlaceSite_CanInPlaceActivate,
1185     InPlaceSite_OnInPlaceActivate,
1186     InPlaceSite_OnUIActivate,
1187     InPlaceSite_GetWindowContext,
1188     InPlaceSite_Scroll,
1189     InPlaceSite_OnUIDeactivate,
1190     InPlaceSite_OnInPlaceDeactivate,
1191     InPlaceSite_DiscardUndoState,
1192     InPlaceSite_DeactivateAndUndo,
1193     InPlaceSite_OnPosRectChange,
1194 };
1195
1196 static IOleInPlaceSite InPlaceSite = { &InPlaceSiteVtbl };
1197
1198 static HRESULT WINAPI ClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv)
1199 {
1200     return QueryInterface(riid, ppv);
1201 }
1202
1203 static ULONG WINAPI ClientSite_AddRef(IOleClientSite *iface)
1204 {
1205     return 2;
1206 }
1207
1208 static ULONG WINAPI ClientSite_Release(IOleClientSite *iface)
1209 {
1210     return 1;
1211 }
1212
1213 static HRESULT WINAPI ClientSite_SaveObject(IOleClientSite *iface)
1214 {
1215     ok(0, "unexpected call\n");
1216     return E_NOTIMPL;
1217 }
1218
1219 static HRESULT WINAPI ClientSite_GetMoniker(IOleClientSite *iface, DWORD dwAssign, DWORD dwWhichMoniker,
1220         IMoniker **ppmon)
1221 {
1222     ok(0, "unexpected call\n");
1223     return E_NOTIMPL;
1224 }
1225
1226 static HRESULT WINAPI ClientSite_GetContainer(IOleClientSite *iface, IOleContainer **ppContainer)
1227 {
1228     return E_NOTIMPL;
1229 }
1230
1231 static HRESULT WINAPI ClientSite_ShowObject(IOleClientSite *iface)
1232 {
1233     ok(0, "unexpected call\n");
1234     return E_NOTIMPL;
1235 }
1236
1237 static HRESULT WINAPI ClientSite_OnShowWindow(IOleClientSite *iface, BOOL fShow)
1238 {
1239     ok(0, "unexpected call\n");
1240     return E_NOTIMPL;
1241 }
1242
1243 static HRESULT WINAPI ClientSite_RequestNewObjectLayout(IOleClientSite *iface)
1244 {
1245     ok(0, "unexpected call\n");
1246     return E_NOTIMPL;
1247 }
1248
1249 static const IOleClientSiteVtbl ClientSiteVtbl = {
1250     ClientSite_QueryInterface,
1251     ClientSite_AddRef,
1252     ClientSite_Release,
1253     ClientSite_SaveObject,
1254     ClientSite_GetMoniker,
1255     ClientSite_GetContainer,
1256     ClientSite_ShowObject,
1257     ClientSite_OnShowWindow,
1258     ClientSite_RequestNewObjectLayout
1259 };
1260
1261 static IOleClientSite ClientSite = { &ClientSiteVtbl };
1262
1263 static HRESULT WINAPI DocumentSite_QueryInterface(IOleDocumentSite *iface, REFIID riid, void **ppv)
1264 {
1265     return QueryInterface(riid, ppv);
1266 }
1267
1268 static ULONG WINAPI DocumentSite_AddRef(IOleDocumentSite *iface)
1269 {
1270     return 2;
1271 }
1272
1273 static ULONG WINAPI DocumentSite_Release(IOleDocumentSite *iface)
1274 {
1275     return 1;
1276 }
1277
1278 static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocumentView *pViewToActivate)
1279 {
1280     RECT rect = {0,0,300,300};
1281     IOleDocument *document;
1282     HRESULT hres;
1283
1284     hres = IOleDocumentView_QueryInterface(pViewToActivate, &IID_IOleDocument, (void**)&document);
1285     ok(hres == S_OK, "could not get IOleDocument: %08x\n", hres);
1286
1287     hres = IOleDocument_CreateView(document, &InPlaceSite, NULL, 0, &view);
1288     IOleDocument_Release(document);
1289     ok(hres == S_OK, "CreateView failed: %08x\n", hres);
1290
1291     hres = IOleDocumentView_SetInPlaceSite(view, &InPlaceSite);
1292     ok(hres == S_OK, "SetInPlaceSite failed: %08x\n", hres);
1293
1294     hres = IOleDocumentView_UIActivate(view, TRUE);
1295     ok(hres == S_OK, "UIActivate failed: %08x\n", hres);
1296
1297     hres = IOleDocumentView_SetRect(view, &rect);
1298     ok(hres == S_OK, "SetRect failed: %08x\n", hres);
1299
1300     hres = IOleDocumentView_Show(view, TRUE);
1301     ok(hres == S_OK, "Show failed: %08x\n", hres);
1302
1303     return S_OK;
1304 }
1305
1306 static const IOleDocumentSiteVtbl DocumentSiteVtbl = {
1307     DocumentSite_QueryInterface,
1308     DocumentSite_AddRef,
1309     DocumentSite_Release,
1310     DocumentSite_ActivateMe
1311 };
1312
1313 static IOleDocumentSite DocumentSite = { &DocumentSiteVtbl };
1314
1315 static HRESULT QueryInterface(REFIID riid, void **ppv)
1316 {
1317     *ppv = NULL;
1318
1319     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IOleClientSite, riid))
1320         *ppv = &ClientSite;
1321     else if(IsEqualGUID(&IID_IOleDocumentSite, riid))
1322         *ppv = &DocumentSite;
1323     else if(IsEqualGUID(&IID_IOleWindow, riid) || IsEqualGUID(&IID_IOleInPlaceSite, riid))
1324         *ppv = &InPlaceSite;
1325
1326     return *ppv ? S_OK : E_NOINTERFACE;
1327 }
1328
1329 static IHTMLDocument2 *notif_doc;
1330 static BOOL doc_complete;
1331
1332 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
1333         REFIID riid, void**ppv)
1334 {
1335     if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
1336         *ppv = iface;
1337         return S_OK;
1338     }
1339
1340     ok(0, "unexpected call\n");
1341     return E_NOINTERFACE;
1342 }
1343
1344 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
1345 {
1346     return 2;
1347 }
1348
1349 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
1350 {
1351     return 1;
1352 }
1353
1354 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
1355 {
1356     if(dispID == DISPID_READYSTATE){
1357         BSTR state;
1358         HRESULT hres;
1359
1360         hres = IHTMLDocument2_get_readyState(notif_doc, &state);
1361         ok(hres == S_OK, "get_readyState failed: %08x\n", hres);
1362
1363         if(!strcmp_wa(state, "complete"))
1364             doc_complete = TRUE;
1365
1366         SysFreeString(state);
1367     }
1368
1369     return S_OK;
1370 }
1371
1372 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
1373 {
1374     ok(0, "unexpected call\n");
1375     return E_NOTIMPL;
1376 }
1377
1378 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
1379     PropertyNotifySink_QueryInterface,
1380     PropertyNotifySink_AddRef,
1381     PropertyNotifySink_Release,
1382     PropertyNotifySink_OnChanged,
1383     PropertyNotifySink_OnRequestEdit
1384 };
1385
1386 static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
1387
1388 static void doc_load_string(IHTMLDocument2 *doc, const char *str)
1389 {
1390     IPersistStreamInit *init;
1391     IStream *stream;
1392     HGLOBAL mem;
1393     SIZE_T len;
1394
1395     notif_doc = doc;
1396
1397     doc_complete = FALSE;
1398     len = strlen(str);
1399     mem = GlobalAlloc(0, len);
1400     memcpy(mem, str, len);
1401     CreateStreamOnHGlobal(mem, TRUE, &stream);
1402
1403     IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init);
1404
1405     IPersistStreamInit_Load(init, stream);
1406     IPersistStreamInit_Release(init);
1407     IStream_Release(stream);
1408 }
1409
1410 static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise)
1411 {
1412     IConnectionPointContainer *container;
1413     IConnectionPoint *cp;
1414     DWORD cookie;
1415     HRESULT hres;
1416
1417     hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container);
1418     ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
1419
1420     hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp);
1421     IConnectionPointContainer_Release(container);
1422     ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
1423
1424     hres = IConnectionPoint_Advise(cp, unk_advise, &cookie);
1425     IConnectionPoint_Release(cp);
1426     ok(hres == S_OK, "Advise failed: %08x\n", hres);
1427 }
1428
1429 static void set_client_site(IHTMLDocument2 *doc, BOOL set)
1430 {
1431     IOleObject *oleobj;
1432     HRESULT hres;
1433
1434     if(!set && view) {
1435         IOleDocumentView_Show(view, FALSE);
1436         IOleDocumentView_CloseView(view, 0);
1437         IOleDocumentView_SetInPlaceSite(view, NULL);
1438         IOleDocumentView_Release(view);
1439         view = NULL;
1440     }
1441
1442     hres = IHTMLDocument2_QueryInterface(doc, &IID_IOleObject, (void**)&oleobj);
1443     ok(hres == S_OK, "Could not et IOleObject: %08x\n", hres);
1444
1445     hres = IOleObject_SetClientSite(oleobj, set ? &ClientSite : NULL);
1446     ok(hres == S_OK, "SetClientSite failed: %08x\n", hres);
1447
1448     if(set) {
1449         IHlinkTarget *hlink;
1450
1451         hres = IOleObject_QueryInterface(oleobj, &IID_IHlinkTarget, (void**)&hlink);
1452         ok(hres == S_OK, "Could not get IHlinkTarget iface: %08x\n", hres);
1453
1454         hres = IHlinkTarget_Navigate(hlink, 0, NULL);
1455         ok(hres == S_OK, "Navgate failed: %08x\n", hres);
1456
1457         IHlinkTarget_Release(hlink);
1458     }
1459
1460     IOleObject_Release(oleobj);
1461 }
1462 static IHTMLDocument2 *create_document(void)
1463 {
1464     IHTMLDocument2 *doc;
1465     HRESULT hres;
1466
1467     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
1468             &IID_IHTMLDocument2, (void**)&doc);
1469     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
1470
1471     return doc;
1472 }
1473
1474
1475 typedef void (*testfunc_t)(IHTMLDocument2*);
1476
1477 static void run_test(const char *str, testfunc_t test)
1478 {
1479     IHTMLDocument2 *doc;
1480     IHTMLElement *body = NULL;
1481     ULONG ref;
1482     MSG msg;
1483     HRESULT hres;
1484
1485     doc = create_document();
1486     set_client_site(doc, TRUE);
1487     doc_load_string(doc, str);
1488     do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
1489
1490     while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
1491         TranslateMessage(&msg);
1492         DispatchMessage(&msg);
1493     }
1494
1495     hres = IHTMLDocument2_get_body(doc, &body);
1496     ok(hres == S_OK, "get_body failed: %08x\n", hres);
1497
1498     if(body) {
1499         IHTMLElement_Release(body);
1500
1501         hres = IHTMLDocument2_get_parentWindow(doc, &window);
1502         ok(hres == S_OK, "get_parentWindow failed: %08x\n", hres);
1503         ok(window != NULL, "window == NULL\n");
1504
1505         test(doc);
1506
1507         IHTMLWindow2_Release(window);
1508         window = NULL;
1509     }else {
1510         skip("Could not get document body. Assuming no Gecko installed.\n");
1511     }
1512
1513     set_client_site(doc, FALSE);
1514     ref = IHTMLDocument2_Release(doc);
1515     ok(!ref, "ref = %d\n", ref);
1516 }
1517
1518 static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1519 {
1520     return DefWindowProc(hwnd, msg, wParam, lParam);
1521 }
1522
1523 static HWND create_container_window(void)
1524 {
1525     static const CHAR szHTMLDocumentTest[] = "HTMLDocumentTest";
1526     static WNDCLASSEXA wndclass = {
1527         sizeof(WNDCLASSEXA),
1528         0,
1529         wnd_proc,
1530         0, 0, NULL, NULL, NULL, NULL, NULL,
1531         szHTMLDocumentTest,
1532         NULL
1533     };
1534
1535     RegisterClassExA(&wndclass);
1536     return CreateWindowA(szHTMLDocumentTest, szHTMLDocumentTest,
1537             WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
1538             300, 300, NULL, NULL, NULL, NULL);
1539 }
1540
1541 START_TEST(events)
1542 {
1543     CoInitialize(NULL);
1544     container_hwnd = create_container_window();
1545
1546     if(winetest_interactive)
1547         ShowWindow(container_hwnd, SW_SHOW);
1548
1549     run_test(empty_doc_str, test_timeout);
1550     run_test(click_doc_str, test_onclick);
1551
1552     DestroyWindow(container_hwnd);
1553     CoUninitialize();
1554 }