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