d0ddadb44da3f7ff3d6300057e117123b684b144
[reactos.git] / rostests / winetests / mshtml / 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 }