|  | /* | 
|  | * Copyright 2008-2009 Jacek Caban for CodeWeavers | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #define COBJMACROS | 
|  | #define CONST_VTABLE | 
|  |  | 
|  | #include <wine/test.h> | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "ole2.h" | 
|  | #include "mshtml.h" | 
|  | #include "docobj.h" | 
|  | #include "hlink.h" | 
|  | #include "dispex.h" | 
|  |  | 
|  | #define DEFINE_EXPECT(func) \ | 
|  | static BOOL expect_ ## func = FALSE, called_ ## func = FALSE | 
|  |  | 
|  | #define SET_EXPECT(func) \ | 
|  | do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) | 
|  |  | 
|  | #define CHECK_EXPECT2(func) \ | 
|  | do { \ | 
|  | trace(#func "\n"); \ | 
|  | ok(expect_ ##func, "unexpected call " #func "\n"); \ | 
|  | called_ ## func = TRUE; \ | 
|  | }while(0) | 
|  |  | 
|  | #define CHECK_EXPECT(func) \ | 
|  | do { \ | 
|  | CHECK_EXPECT2(func); \ | 
|  | expect_ ## func = FALSE; \ | 
|  | }while(0) | 
|  |  | 
|  | #define CHECK_CALLED(func) \ | 
|  | do { \ | 
|  | ok(called_ ## func, "expected " #func "\n"); \ | 
|  | expect_ ## func = called_ ## func = FALSE; \ | 
|  | }while(0) | 
|  |  | 
|  | DEFINE_EXPECT(document_onclick); | 
|  | DEFINE_EXPECT(body_onclick); | 
|  | DEFINE_EXPECT(div_onclick); | 
|  | DEFINE_EXPECT(div_onclick_attached); | 
|  | DEFINE_EXPECT(timeout); | 
|  |  | 
|  | static HWND container_hwnd = NULL; | 
|  | static IHTMLWindow2 *window; | 
|  | static IOleDocumentView *view; | 
|  |  | 
|  | typedef struct { | 
|  | LONG x; | 
|  | LONG y; | 
|  | LONG offset_x; | 
|  | LONG offset_y; | 
|  | } xy_test_t; | 
|  |  | 
|  | static const xy_test_t no_xy = {-10,-10,-10,-10}; | 
|  | static const xy_test_t zero_xy = {0,0,0,0}; | 
|  |  | 
|  | static const char empty_doc_str[] = | 
|  | "<html></html>"; | 
|  |  | 
|  | static const char click_doc_str[] = | 
|  | "<html><body>" | 
|  | "<div id=\"clickdiv\" style=\"text-align: center; background: red; font-size: 32\">click here</div>" | 
|  | "</body></html>"; | 
|  |  | 
|  | static const char *debugstr_w(LPCWSTR str) | 
|  | { | 
|  | static char buf[1024]; | 
|  | WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); | 
|  | return buf; | 
|  | } | 
|  |  | 
|  | static const char *debugstr_guid(REFIID riid) | 
|  | { | 
|  | static char buf[50]; | 
|  |  | 
|  | sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", | 
|  | riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], | 
|  | riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4], | 
|  | riid->Data4[5], riid->Data4[6], riid->Data4[7]); | 
|  |  | 
|  | return buf; | 
|  | } | 
|  |  | 
|  | static int strcmp_wa(LPCWSTR strw, const char *stra) | 
|  | { | 
|  | CHAR buf[512]; | 
|  | WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL); | 
|  | return lstrcmpA(stra, buf); | 
|  | } | 
|  |  | 
|  | static BSTR a2bstr(const char *str) | 
|  | { | 
|  | BSTR ret; | 
|  | int len; | 
|  |  | 
|  | len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); | 
|  | ret = SysAllocStringLen(NULL, len-1); | 
|  | MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2) | 
|  | { | 
|  | IUnknown *unk1, *unk2; | 
|  |  | 
|  | if(iface1 == iface2) | 
|  | return TRUE; | 
|  |  | 
|  | IUnknown_QueryInterface(iface1, &IID_IUnknown, (void**)&unk1); | 
|  | IUnknown_Release(unk1); | 
|  | IUnknown_QueryInterface(iface1, &IID_IUnknown, (void**)&unk2); | 
|  | IUnknown_Release(unk2); | 
|  |  | 
|  | return unk1 == unk2; | 
|  | } | 
|  |  | 
|  | #define test_disp(u,id) _test_disp(__LINE__,u,id) | 
|  | static void _test_disp(unsigned line, IUnknown *unk, const IID *diid) | 
|  | { | 
|  | IDispatchEx *dispex; | 
|  | ITypeInfo *typeinfo; | 
|  | UINT ticnt; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex); | 
|  | ok_(__FILE__,line) (hres == S_OK, "Could not get IDispatch: %08x\n", hres); | 
|  | if(FAILED(hres)) | 
|  | return; | 
|  |  | 
|  | ticnt = 0xdeadbeef; | 
|  | hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt); | 
|  | ok_(__FILE__,line) (hres == S_OK, "GetTypeInfoCount failed: %08x\n", hres); | 
|  | ok_(__FILE__,line) (ticnt == 1, "ticnt=%u\n", ticnt); | 
|  |  | 
|  | hres = IDispatchEx_GetTypeInfo(dispex, 0, 0, &typeinfo); | 
|  | ok_(__FILE__,line) (hres == S_OK, "GetTypeInfo failed: %08x\n", hres); | 
|  |  | 
|  | if(SUCCEEDED(hres)) { | 
|  | TYPEATTR *type_attr; | 
|  |  | 
|  | hres = ITypeInfo_GetTypeAttr(typeinfo, &type_attr); | 
|  | ok_(__FILE__,line) (hres == S_OK, "GetTypeAttr failed: %08x\n", hres); | 
|  | ok_(__FILE__,line) (IsEqualGUID(&type_attr->guid, diid), "unexpected guid %s\n", | 
|  | debugstr_guid(&type_attr->guid)); | 
|  |  | 
|  | ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr); | 
|  | ITypeInfo_Release(typeinfo); | 
|  | } | 
|  |  | 
|  | IDispatchEx_Release(dispex); | 
|  | } | 
|  |  | 
|  | #define get_doc3_iface(u) _get_doc3_iface(__LINE__,u) | 
|  | static IHTMLDocument3 *_get_doc3_iface(unsigned line, IUnknown *unk) | 
|  | { | 
|  | IHTMLDocument3 *doc3; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IUnknown_QueryInterface(unk, &IID_IHTMLDocument3, (void**)&doc3); | 
|  | ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDocument3 iface: %08x\n", hres); | 
|  |  | 
|  | return doc3; | 
|  | } | 
|  |  | 
|  | #define get_elem_iface(u) _get_elem_iface(__LINE__,u) | 
|  | static IHTMLElement *_get_elem_iface(unsigned line, IUnknown *unk) | 
|  | { | 
|  | IHTMLElement *elem; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement, (void**)&elem); | 
|  | ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement iface: %08x\n", hres); | 
|  |  | 
|  | return elem; | 
|  | } | 
|  |  | 
|  | #define get_elem2_iface(u) _get_elem2_iface(__LINE__,u) | 
|  | static IHTMLElement2 *_get_elem2_iface(unsigned line, IUnknown *unk) | 
|  | { | 
|  | IHTMLElement2 *elem2; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement2, (void**)&elem2); | 
|  | ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement2 iface: %08x\n", hres); | 
|  |  | 
|  | return elem2; | 
|  | } | 
|  |  | 
|  | #define doc_get_body(d) _doc_get_body(__LINE__,d) | 
|  | static IHTMLElement *_doc_get_body(unsigned line, IHTMLDocument2 *doc) | 
|  | { | 
|  | IHTMLElement *body = NULL; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLDocument2_get_body(doc, &body); | 
|  | ok_(__FILE__,line) (hres == S_OK, "get_body failed: %08x\n", hres); | 
|  | ok_(__FILE__,line) (body != NULL, "body == NULL\n"); | 
|  |  | 
|  | return body; | 
|  | } | 
|  |  | 
|  | #define get_elem_id(d,i) _get_elem_id(__LINE__,d,i) | 
|  | static IHTMLElement *_get_elem_id(unsigned line, IHTMLDocument2 *doc, const char *id) | 
|  | { | 
|  | IHTMLDocument3 *doc3 = _get_doc3_iface(line, (IUnknown*)doc); | 
|  | IHTMLElement *elem; | 
|  | BSTR str; | 
|  | HRESULT hres; | 
|  |  | 
|  | str = a2bstr(id); | 
|  | hres = IHTMLDocument3_getElementById(doc3, str, &elem); | 
|  | SysFreeString(str); | 
|  | IHTMLDocument3_Release(doc3); | 
|  | ok_(__FILE__,line) (hres == S_OK, "getElementById failed: %08x\n", hres); | 
|  |  | 
|  | return elem; | 
|  | } | 
|  |  | 
|  | #define test_elem_tag(u,n) _test_elem_tag(__LINE__,u,n) | 
|  | static void _test_elem_tag(unsigned line, IUnknown *unk, const char *extag) | 
|  | { | 
|  | IHTMLElement *elem = _get_elem_iface(line, unk); | 
|  | BSTR tag; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLElement_get_tagName(elem, &tag); | 
|  | IHTMLElement_Release(elem); | 
|  | ok_(__FILE__, line) (hres == S_OK, "get_tagName failed: %08x\n", hres); | 
|  | ok_(__FILE__, line) (!strcmp_wa(tag, extag), "got tag: %s, expected %s\n", debugstr_w(tag), extag); | 
|  |  | 
|  | SysFreeString(tag); | 
|  | } | 
|  |  | 
|  | #define get_event_obj() _get_event_obj(__LINE__) | 
|  | static IHTMLEventObj *_get_event_obj(unsigned line) | 
|  | { | 
|  | IHTMLEventObj *event = NULL; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLWindow2_get_event(window, &event); | 
|  | ok_(__FILE__,line) (hres == S_OK, "get_event failed: %08x\n", hres); | 
|  | ok_(__FILE__,line) (event != NULL, "event = NULL\n"); | 
|  | _test_disp(line, (IUnknown*)event, &DIID_DispCEventObj); | 
|  |  | 
|  | return event; | 
|  | } | 
|  |  | 
|  | #define test_event_args(a,b,c,d,e,f,g) _test_event_args(__LINE__,a,b,c,d,e,f,g) | 
|  | static void _test_event_args(unsigned line, const IID *dispiid, DISPID id, WORD wFlags, DISPPARAMS *pdp, | 
|  | VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) | 
|  | { | 
|  | ok_(__FILE__,line) (id == DISPID_VALUE, "id = %d\n", id); | 
|  | ok_(__FILE__,line) (wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); | 
|  | ok_(__FILE__,line) (pdp != NULL, "pdp == NULL\n"); | 
|  | ok_(__FILE__,line) (pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs); | 
|  | ok_(__FILE__,line) (pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); | 
|  | ok_(__FILE__,line) (pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %d\n", | 
|  | pdp->rgdispidNamedArgs[0]); | 
|  | ok_(__FILE__,line) (V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); | 
|  | ok_(__FILE__,line) (pvarRes != NULL, "pvarRes == NULL\n"); | 
|  | ok_(__FILE__,line) (pei != NULL, "pei == NULL"); | 
|  | ok_(__FILE__,line) (!pspCaller, "pspCaller != NULL\n"); | 
|  |  | 
|  | if(dispiid) | 
|  | _test_disp(line, (IUnknown*)V_DISPATCH(pdp->rgvarg), dispiid); | 
|  | } | 
|  |  | 
|  | #define test_attached_event_args(a,b,c,d,e) _test_attached_event_args(__LINE__,a,b,c,d,e) | 
|  | static void _test_attached_event_args(unsigned line, DISPID id, WORD wFlags, DISPPARAMS *pdp, | 
|  | VARIANT *pvarRes, EXCEPINFO *pei) | 
|  | { | 
|  | IHTMLEventObj *event; | 
|  |  | 
|  | ok(id == DISPID_VALUE, "id = %d\n", id); | 
|  | ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); | 
|  | ok(pdp != NULL, "pDispParams == NULL\n"); | 
|  | ok(pdp->cArgs == 1, "pdp->cArgs = %d\n", pdp->cArgs); | 
|  | ok(!pdp->cNamedArgs, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); | 
|  | ok(!pdp->rgdispidNamedArgs, "pdp->rgdispidNamedArgs = %p\n", pdp->rgdispidNamedArgs); | 
|  | ok(pdp->rgvarg != NULL, "rgvarg = NULL\n"); | 
|  | ok(pvarRes != NULL, "pvarRes = NULL\n"); | 
|  | ok(pei != NULL, "pei = NULL\n"); | 
|  | ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pVarRes) = %d\n", V_VT(pvarRes)); | 
|  | ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(pdp->rgvarg) = %d\n", V_VT(pdp->rgvarg)); | 
|  | ok(V_DISPATCH(pdp->rgvarg) != NULL, "V_DISPATCH(pdp->rgvarg) = %p\n", V_DISPATCH(pdp->rgvarg)); | 
|  |  | 
|  | event = _get_event_obj(line); | 
|  | ok(iface_cmp((IUnknown*)event, (IUnknown*)V_DISPATCH(pdp->rgvarg)), "event != arg0\n"); | 
|  | IHTMLEventObj_Release(event); | 
|  | } | 
|  |  | 
|  | #define test_event_src(t) _test_event_src(__LINE__,t) | 
|  | static void _test_event_src(unsigned line, const char *src_tag) | 
|  | { | 
|  | IHTMLEventObj *event = _get_event_obj(line); | 
|  | IHTMLElement *src_elem = NULL; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_srcElement(event, &src_elem); | 
|  | IHTMLEventObj_Release(event); | 
|  | ok_(__FILE__,line) (hres == S_OK, "get_srcElement failed: %08x\n", hres); | 
|  |  | 
|  | if(src_tag) { | 
|  | ok_(__FILE__,line) (src_elem != NULL, "src_elem = NULL\n"); | 
|  | _test_elem_tag(line, (IUnknown*)src_elem, src_tag); | 
|  | IHTMLElement_Release(src_elem); | 
|  | }else { | 
|  | ok_(__FILE__,line) (!src_elem, "src_elem != NULL\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void _test_event_altkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval) | 
|  | { | 
|  | VARIANT_BOOL b; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_altKey(event, &b); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_altKey failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(b == exval, "altKey = %x, expected %x\n", b, exval); | 
|  | } | 
|  |  | 
|  | static void _test_event_ctrlkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval) | 
|  | { | 
|  | VARIANT_BOOL b; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_ctrlKey(event, &b); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_ctrlKey failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(b == exval, "ctrlKey = %x, expected %x\n", b, exval); | 
|  | } | 
|  |  | 
|  | static void _test_event_shiftkey(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval) | 
|  | { | 
|  | VARIANT_BOOL b; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_shiftKey(event, &b); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_shiftKey failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(b == exval, "shiftKey = %x, expected %x\n", b, exval); | 
|  | } | 
|  |  | 
|  | static void _test_event_cancelbubble(unsigned line, IHTMLEventObj *event, VARIANT_BOOL exval) | 
|  | { | 
|  | VARIANT_BOOL b; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_cancelBubble(event, &b); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_cancelBubble failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(b == exval, "cancelBubble = %x, expected %x\n", b, exval); | 
|  | } | 
|  |  | 
|  | static void _test_event_fromelem(unsigned line, IHTMLEventObj *event, const char *from_tag) | 
|  | { | 
|  | IHTMLElement *elem; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_fromElement(event, &elem); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_fromElement failed: %08x\n", hres); | 
|  | if(from_tag) | 
|  | _test_elem_tag(line, (IUnknown*)elem, from_tag); | 
|  | else | 
|  | ok_(__FILE__,line)(elem == NULL, "fromElement != NULL\n"); | 
|  | if(elem) | 
|  | IHTMLElement_Release(elem); | 
|  | } | 
|  |  | 
|  | static void _test_event_toelem(unsigned line, IHTMLEventObj *event, const char *to_tag) | 
|  | { | 
|  | IHTMLElement *elem; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_toElement(event, &elem); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_toElement failed: %08x\n", hres); | 
|  | if(to_tag) | 
|  | _test_elem_tag(line, (IUnknown*)elem, to_tag); | 
|  | else | 
|  | ok_(__FILE__,line)(elem == NULL, "toElement != NULL\n"); | 
|  | if(elem) | 
|  | IHTMLElement_Release(elem); | 
|  | } | 
|  |  | 
|  | static void _test_event_keycode(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_keyCode(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_keyCode failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(l == exl, "keyCode = %x, expected %x\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_button(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_button(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_button failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(l == exl, "button = %x, expected %x\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_reason(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_reason(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_reason failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(l == exl, "reason = %x, expected %x\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_x(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_x(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_x failed: %08x\n", hres); | 
|  | if(exl == -10) /* don't test the exact value */ | 
|  | todo_wine ok_(__FILE__,line)(l > 0, "x = %d\n", l); | 
|  | else | 
|  | ok_(__FILE__,line)(l == exl, "x = %d, expected %d\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_y(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_y(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_y failed: %08x\n", hres); | 
|  | if(exl == -10) /* don't test the exact value */ | 
|  | todo_wine ok_(__FILE__,line)(l > 0, "y = %d\n", l); | 
|  | else | 
|  | ok_(__FILE__,line)(l == exl, "y = %d, expected %d\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_clientx(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_clientX(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_clientX failed: %08x\n", hres); | 
|  | if(exl == -10) /* don't test the exact value */ | 
|  | ok_(__FILE__,line)(l > 0, "clientX = %d\n", l); | 
|  | else | 
|  | ok_(__FILE__,line)(l == exl, "clientX = %d, expected %d\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_clienty(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_clientY(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_clientY failed: %08x\n", hres); | 
|  | if(exl == -10) /* don't test the exact value */ | 
|  | ok_(__FILE__,line)(l > 0, "clientY = %d\n", l); | 
|  | else | 
|  | ok_(__FILE__,line)(l == exl, "clientY = %d, expected %d\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_offsetx(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_offsetX(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_offsetX failed: %08x\n", hres); | 
|  | if(exl == -10) /* don't test the exact value */ | 
|  | todo_wine ok_(__FILE__,line)(l > 0, "offsetX = %d\n", l); | 
|  | else | 
|  | ok_(__FILE__,line)(l == exl, "offsetX = %d, expected %d\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_offsety(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_offsetY(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_offsetY failed: %08x\n", hres); | 
|  | if(exl == -10) /* don't test the exact value */ | 
|  | todo_wine ok_(__FILE__,line)(l > 0, "offsetY = %d\n", l); | 
|  | else | 
|  | ok_(__FILE__,line)(l == exl, "offsetY = %d, expected %d\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_screenx(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_screenX(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_screenX failed: %08x\n", hres); | 
|  | if(exl == -10) /* don't test the exact value */ | 
|  | ok_(__FILE__,line)(l > 0, "screenX = %d\n", l); | 
|  | else | 
|  | ok_(__FILE__,line)(l == exl, "screenX = %d, expected %d\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_screeny(unsigned line, IHTMLEventObj *event, LONG exl) | 
|  | { | 
|  | LONG l; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_screenY(event, &l); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_screenY failed: %08x\n", hres); | 
|  | if(exl == -10) /* don't test the exact value */ | 
|  | ok_(__FILE__,line)(l > 0, "screenY = %d\n", l); | 
|  | else | 
|  | ok_(__FILE__,line)(l == exl, "screenY = %d, expected %d\n", l, exl); | 
|  | } | 
|  |  | 
|  | static void _test_event_type(unsigned line, IHTMLEventObj *event, const char *exstr) | 
|  | { | 
|  | BSTR str; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_type(event, &str); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_type failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(!strcmp_wa(str, exstr), "type = %s, expected %s\n", wine_dbgstr_w(str), exstr); | 
|  | } | 
|  |  | 
|  | static void _test_event_qualifier(unsigned line, IHTMLEventObj *event, const char *exstr) | 
|  | { | 
|  | BSTR str; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_qualifier(event, &str); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_qualifier failed: %08x\n", hres); | 
|  | if(exstr) | 
|  | ok_(__FILE__,line)(!strcmp_wa(str, exstr), "qualifier = %s, expected %s\n", wine_dbgstr_w(str), exstr); | 
|  | else | 
|  | ok_(__FILE__,line)(!str, "qualifier != NULL\n"); | 
|  | } | 
|  |  | 
|  | static void _test_event_srcfilter(unsigned line, IHTMLEventObj *event) | 
|  | { | 
|  | IDispatch *disp; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLEventObj_get_srcFilter(event, &disp); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_srcFilter failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(!disp, "srcFilter != NULL\n"); | 
|  | } | 
|  |  | 
|  | #define test_event_obj(t,x) _test_event_obj(__LINE__,t,x) | 
|  | static void _test_event_obj(unsigned line, const char *type, const xy_test_t *xy) | 
|  | { | 
|  | IHTMLEventObj *event = _get_event_obj(line); | 
|  | VARIANT v; | 
|  | HRESULT hres; | 
|  |  | 
|  | _test_event_altkey(line, event, VARIANT_FALSE); | 
|  | _test_event_ctrlkey(line, event, VARIANT_FALSE); | 
|  | _test_event_shiftkey(line, event, VARIANT_FALSE); | 
|  | _test_event_cancelbubble(line, event, VARIANT_FALSE); | 
|  | _test_event_fromelem(line, event, NULL); | 
|  | _test_event_toelem(line, event, NULL); | 
|  | _test_event_keycode(line, event, 0); | 
|  | _test_event_button(line, event, 0); | 
|  | _test_event_type(line, event, type); | 
|  | _test_event_qualifier(line, event, NULL); | 
|  | _test_event_reason(line, event, 0); | 
|  | _test_event_srcfilter(line, event); | 
|  | _test_event_x(line, event, xy->x); | 
|  | _test_event_y(line, event, xy->y); | 
|  | _test_event_clientx(line, event, -10); | 
|  | _test_event_clienty(line, event, -10); | 
|  | _test_event_offsetx(line, event, xy->offset_x); | 
|  | _test_event_offsety(line, event, xy->offset_y); | 
|  | _test_event_screenx(line, event, -10); | 
|  | _test_event_screeny(line, event, -10); | 
|  |  | 
|  | hres = IHTMLEventObj_get_returnValue(event, &v); | 
|  | ok_(__FILE__,line)(hres == S_OK, "get_returnValue failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(V_VT(&v) == VT_EMPTY, "V_VT(returnValue) = %d\n", V_VT(&v)); | 
|  |  | 
|  | IHTMLEventObj_Release(event); | 
|  | } | 
|  |  | 
|  | #define elem_attach_event(a,b,c) _elem_attach_event(__LINE__,a,b,c) | 
|  | static void _elem_attach_event(unsigned line, IUnknown *unk, const char *namea, IDispatch *disp) | 
|  | { | 
|  | IHTMLElement2 *elem = _get_elem2_iface(line, unk); | 
|  | VARIANT_BOOL res; | 
|  | BSTR name; | 
|  | HRESULT hres; | 
|  |  | 
|  | name = a2bstr(namea); | 
|  | hres = IHTMLElement2_attachEvent(elem, name, disp, &res); | 
|  | IHTMLElement2_Release(elem); | 
|  | SysFreeString(name); | 
|  | ok_(__FILE__,line)(hres == S_OK, "attachEvent failed: %08x\n", hres); | 
|  | ok_(__FILE__,line)(res == VARIANT_TRUE, "attachEvent returned %x\n", res); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) | 
|  | { | 
|  | *ppv = NULL; | 
|  |  | 
|  | if(IsEqualGUID(riid, &IID_IUnknown) | 
|  | || IsEqualGUID(riid, &IID_IDispatch) | 
|  | || IsEqualGUID(riid, &IID_IDispatchEx)) | 
|  | *ppv = iface; | 
|  | else { | 
|  | ok(0, "unexpected riid %s\n", debugstr_guid(riid)); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) | 
|  | { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, | 
|  | LCID lcid, ITypeInfo **ppTInfo) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, | 
|  | LPOLESTR *rgszNames, UINT cNames, | 
|  | LCID lcid, DISPID *rgDispId) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, | 
|  | REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, | 
|  | VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, | 
|  | VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) | 
|  | { | 
|  | ok(0, "unexpected call %s %x\n", debugstr_w(bstrName), grfdex); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | #define EVENT_HANDLER_FUNC_OBJ(event) \ | 
|  | static IDispatchExVtbl event ## FuncVtbl = { \ | 
|  | DispatchEx_QueryInterface, \ | 
|  | DispatchEx_AddRef, \ | 
|  | DispatchEx_Release, \ | 
|  | DispatchEx_GetTypeInfoCount, \ | 
|  | DispatchEx_GetTypeInfo, \ | 
|  | DispatchEx_GetIDsOfNames, \ | 
|  | DispatchEx_Invoke, \ | 
|  | DispatchEx_GetDispID, \ | 
|  | event, \ | 
|  | DispatchEx_DeleteMemberByName, \ | 
|  | DispatchEx_DeleteMemberByDispID, \ | 
|  | DispatchEx_GetMemberProperties, \ | 
|  | DispatchEx_GetMemberName, \ | 
|  | DispatchEx_GetNextDispID, \ | 
|  | DispatchEx_GetNameSpaceParent \ | 
|  | }; \ | 
|  | static IDispatchEx event ## _obj = { &event ## FuncVtbl }; | 
|  |  | 
|  | static HRESULT WINAPI document_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, | 
|  | VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) | 
|  | { | 
|  | IHTMLDocument3 *doc3; | 
|  | CHECK_EXPECT(document_onclick); | 
|  | test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); | 
|  | doc3 = get_doc3_iface((IUnknown*)V_DISPATCH(pdp->rgvarg)); | 
|  | IHTMLDocument3_Release(doc3); | 
|  | test_event_src("DIV"); | 
|  | test_event_obj("click", &no_xy); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | EVENT_HANDLER_FUNC_OBJ(document_onclick); | 
|  |  | 
|  | static HRESULT WINAPI div_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, | 
|  | VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) | 
|  | { | 
|  | CHECK_EXPECT(div_onclick); | 
|  | test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); | 
|  | test_event_src("DIV"); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | EVENT_HANDLER_FUNC_OBJ(div_onclick); | 
|  |  | 
|  | static HRESULT WINAPI div_onclick_attached(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, | 
|  | VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) | 
|  | { | 
|  | CHECK_EXPECT(div_onclick_attached); | 
|  |  | 
|  | test_attached_event_args(id, wFlags, pdp, pvarRes, pei); | 
|  | test_event_src("DIV"); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | EVENT_HANDLER_FUNC_OBJ(div_onclick_attached); | 
|  |  | 
|  | static HRESULT WINAPI body_onclick(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, | 
|  | VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) | 
|  | { | 
|  | CHECK_EXPECT(body_onclick); | 
|  | test_event_args(&DIID_DispHTMLBody, id, wFlags, pdp, pvarRes, pei, pspCaller); | 
|  | test_event_src("DIV"); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | EVENT_HANDLER_FUNC_OBJ(body_onclick); | 
|  |  | 
|  | static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, | 
|  | VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | EVENT_HANDLER_FUNC_OBJ(nocall); | 
|  |  | 
|  | static HRESULT WINAPI timeoutFunc_Invoke(IDispatchEx *iface, DISPID dispIdMember, | 
|  | REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, | 
|  | VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) | 
|  | { | 
|  | CHECK_EXPECT(timeout); | 
|  |  | 
|  | ok(dispIdMember == DISPID_VALUE, "dispIdMember = %d\n", dispIdMember); | 
|  | ok(IsEqualGUID(&IID_NULL, riid), "riid = %s\n", debugstr_guid(riid)); | 
|  | ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); | 
|  | ok(!lcid, "lcid = %x\n", lcid); | 
|  | ok(pDispParams != NULL, "pDispParams == NULL\n"); | 
|  | ok(!pDispParams->cArgs, "pdp->cArgs = %d\n", pDispParams->cArgs); | 
|  | ok(!pDispParams->cNamedArgs, "pdp->cNamedArgs = %d\n", pDispParams->cNamedArgs); | 
|  | ok(!pDispParams->rgdispidNamedArgs, "pdp->rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs); | 
|  | ok(!pDispParams->rgvarg, "rgvarg = %p\n", pDispParams->rgvarg); | 
|  | ok(pVarResult != NULL, "pVarResult = NULL\n"); | 
|  | ok(pExcepInfo != NULL, "pExcepInfo = NULL\n"); | 
|  | ok(!puArgErr, "puArgErr = %p\n", puArgErr); | 
|  | ok(V_VT(pVarResult) == VT_EMPTY, "V_VT(pVarResult) = %d\n", V_VT(pVarResult)); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static IDispatchExVtbl timeoutFuncVtbl = { | 
|  | DispatchEx_QueryInterface, | 
|  | DispatchEx_AddRef, | 
|  | DispatchEx_Release, | 
|  | DispatchEx_GetTypeInfoCount, | 
|  | DispatchEx_GetTypeInfo, | 
|  | DispatchEx_GetIDsOfNames, | 
|  | timeoutFunc_Invoke, | 
|  | DispatchEx_GetDispID, | 
|  | DispatchEx_InvokeEx, | 
|  | DispatchEx_DeleteMemberByName, | 
|  | DispatchEx_DeleteMemberByDispID, | 
|  | DispatchEx_GetMemberProperties, | 
|  | DispatchEx_GetMemberName, | 
|  | DispatchEx_GetNextDispID, | 
|  | DispatchEx_GetNameSpaceParent | 
|  | }; | 
|  |  | 
|  | static IDispatchEx timeoutFunc = { &timeoutFuncVtbl }; | 
|  |  | 
|  | static void pump_msgs(BOOL *b) | 
|  | { | 
|  | MSG msg; | 
|  | while(!*b && GetMessage(&msg, NULL, 0, 0)) { | 
|  | TranslateMessage(&msg); | 
|  | DispatchMessage(&msg); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void test_onclick(IHTMLDocument2 *doc) | 
|  | { | 
|  | IHTMLElement *div, *body; | 
|  | VARIANT v; | 
|  | HRESULT hres; | 
|  |  | 
|  | div = get_elem_id(doc, "clickdiv"); | 
|  |  | 
|  | elem_attach_event((IUnknown*)div, "abcde", (IDispatch*)&nocall_obj); | 
|  | elem_attach_event((IUnknown*)div, "onclick", (IDispatch*)&div_onclick_attached_obj); | 
|  |  | 
|  | V_VT(&v) = VT_EMPTY; | 
|  | hres = IHTMLElement_get_onclick(div, &v); | 
|  | ok(hres == S_OK, "get_onclick failed: %08x\n", hres); | 
|  | ok(V_VT(&v) == VT_NULL, "V_VT(onclick) = %d\n", V_VT(&v)); | 
|  |  | 
|  | V_VT(&v) = VT_DISPATCH; | 
|  | V_DISPATCH(&v) = (IDispatch*)&div_onclick_obj; | 
|  | hres = IHTMLElement_put_onclick(div, v); | 
|  | ok(hres == S_OK, "put_onclick failed: %08x\n", hres); | 
|  |  | 
|  | V_VT(&v) = VT_EMPTY; | 
|  | hres = IHTMLElement_get_onclick(div, &v); | 
|  | ok(hres == S_OK, "get_onclick failed: %08x\n", hres); | 
|  | ok(V_VT(&v) == VT_DISPATCH, "V_VT(onclick) = %d\n", V_VT(&v)); | 
|  | ok(V_DISPATCH(&v) == (IDispatch*)&div_onclick_obj, "V_DISPATCH(onclick) != onclickFunc\n"); | 
|  | VariantClear(&v); | 
|  |  | 
|  | V_VT(&v) = VT_EMPTY; | 
|  | hres = IHTMLDocument2_get_onclick(doc, &v); | 
|  | ok(hres == S_OK, "get_onclick failed: %08x\n", hres); | 
|  | ok(V_VT(&v) == VT_NULL, "V_VT(onclick) = %d\n", V_VT(&v)); | 
|  |  | 
|  | V_VT(&v) = VT_DISPATCH; | 
|  | V_DISPATCH(&v) = (IDispatch*)&document_onclick_obj; | 
|  | hres = IHTMLDocument2_put_onclick(doc, v); | 
|  | ok(hres == S_OK, "put_onclick failed: %08x\n", hres); | 
|  |  | 
|  | V_VT(&v) = VT_EMPTY; | 
|  | hres = IHTMLDocument2_get_onclick(doc, &v); | 
|  | ok(hres == S_OK, "get_onclick failed: %08x\n", hres); | 
|  | ok(V_VT(&v) == VT_DISPATCH, "V_VT(onclick) = %d\n", V_VT(&v)); | 
|  | ok(V_DISPATCH(&v) == (IDispatch*)&document_onclick_obj, "V_DISPATCH(onclick) != onclickFunc\n"); | 
|  | VariantClear(&v); | 
|  |  | 
|  | body = doc_get_body(doc); | 
|  |  | 
|  | V_VT(&v) = VT_DISPATCH; | 
|  | V_DISPATCH(&v) = (IDispatch*)&body_onclick_obj; | 
|  | hres = IHTMLElement_put_onclick(body, v); | 
|  | ok(hres == S_OK, "put_onclick failed: %08x\n", hres); | 
|  |  | 
|  | if(winetest_interactive) { | 
|  | SET_EXPECT(div_onclick); | 
|  | SET_EXPECT(div_onclick_attached); | 
|  | SET_EXPECT(body_onclick); | 
|  | SET_EXPECT(document_onclick); | 
|  | pump_msgs(&called_document_onclick); | 
|  | CHECK_CALLED(div_onclick); | 
|  | CHECK_CALLED(div_onclick_attached); | 
|  | CHECK_CALLED(body_onclick); | 
|  | CHECK_CALLED(document_onclick); | 
|  | } | 
|  |  | 
|  | IHTMLElement_Release(div); | 
|  | IHTMLElement_Release(body); | 
|  | } | 
|  |  | 
|  | static void test_timeout(IHTMLDocument2 *doc) | 
|  | { | 
|  | IHTMLWindow3 *win3; | 
|  | VARIANT expr, var; | 
|  | LONG id; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow3, (void**)&win3); | 
|  | ok(hres == S_OK, "Could not get IHTMLWindow3 iface: %08x\n", hres); | 
|  |  | 
|  | V_VT(&expr) = VT_DISPATCH; | 
|  | V_DISPATCH(&expr) = (IDispatch*)&timeoutFunc; | 
|  | V_VT(&var) = VT_EMPTY; | 
|  | id = 0; | 
|  | hres = IHTMLWindow3_setTimeout(win3, &expr, 0, &var, &id); | 
|  | ok(hres == S_OK, "setTimeout failed: %08x\n", hres); | 
|  | ok(id, "id = 0\n"); | 
|  |  | 
|  | SET_EXPECT(timeout); | 
|  | pump_msgs(&called_timeout); | 
|  | CHECK_CALLED(timeout); | 
|  |  | 
|  | V_VT(&expr) = VT_DISPATCH; | 
|  | V_DISPATCH(&expr) = (IDispatch*)&timeoutFunc; | 
|  | V_VT(&var) = VT_EMPTY; | 
|  | id = 0; | 
|  | hres = IHTMLWindow3_setTimeout(win3, &expr, 0, &var, &id); | 
|  | ok(hres == S_OK, "setTimeout failed: %08x\n", hres); | 
|  | ok(id, "id = 0\n"); | 
|  |  | 
|  | hres = IHTMLWindow2_clearTimeout(window, id); | 
|  | ok(hres == S_OK, "clearTimeout failed: %08x\n", hres); | 
|  |  | 
|  | IHTMLWindow3_Release(win3); | 
|  | } | 
|  |  | 
|  | static HRESULT QueryInterface(REFIID,void**); | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_QueryInterface(IOleInPlaceFrame *iface, REFIID riid, void **ppv) | 
|  | { | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI InPlaceFrame_AddRef(IOleInPlaceFrame *iface) | 
|  | { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI InPlaceFrame_Release(IOleInPlaceFrame *iface) | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_ContextSensitiveHelp(IOleInPlaceFrame *iface, BOOL fEnterMode) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_GetBorder(IOleInPlaceFrame *iface, LPRECT lprectBorder) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_RequestBorderSpace(IOleInPlaceFrame *iface, | 
|  | LPCBORDERWIDTHS pborderwidths) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_SetBorderSpace(IOleInPlaceFrame *iface, | 
|  | LPCBORDERWIDTHS pborderwidths) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceUIWindow_SetActiveObject(IOleInPlaceFrame *iface, | 
|  | IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_SetActiveObject(IOleInPlaceFrame *iface, | 
|  | IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_InsertMenus(IOleInPlaceFrame *iface, HMENU hmenuShared, | 
|  | LPOLEMENUGROUPWIDTHS lpMenuWidths) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_SetMenu(IOleInPlaceFrame *iface, HMENU hmenuShared, | 
|  | HOLEMENU holemenu, HWND hwndActiveObject) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_RemoveMenus(IOleInPlaceFrame *iface, HMENU hmenuShared) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_SetStatusText(IOleInPlaceFrame *iface, LPCOLESTR pszStatusText) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_EnableModeless(IOleInPlaceFrame *iface, BOOL fEnable) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceFrame_TranslateAccelerator(IOleInPlaceFrame *iface, LPMSG lpmsg, WORD wID) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IOleInPlaceFrameVtbl InPlaceFrameVtbl = { | 
|  | InPlaceFrame_QueryInterface, | 
|  | InPlaceFrame_AddRef, | 
|  | InPlaceFrame_Release, | 
|  | InPlaceFrame_GetWindow, | 
|  | InPlaceFrame_ContextSensitiveHelp, | 
|  | InPlaceFrame_GetBorder, | 
|  | InPlaceFrame_RequestBorderSpace, | 
|  | InPlaceFrame_SetBorderSpace, | 
|  | InPlaceFrame_SetActiveObject, | 
|  | InPlaceFrame_InsertMenus, | 
|  | InPlaceFrame_SetMenu, | 
|  | InPlaceFrame_RemoveMenus, | 
|  | InPlaceFrame_SetStatusText, | 
|  | InPlaceFrame_EnableModeless, | 
|  | InPlaceFrame_TranslateAccelerator | 
|  | }; | 
|  |  | 
|  | static IOleInPlaceFrame InPlaceFrame = { &InPlaceFrameVtbl }; | 
|  |  | 
|  | static const IOleInPlaceFrameVtbl InPlaceUIWindowVtbl = { | 
|  | InPlaceFrame_QueryInterface, | 
|  | InPlaceFrame_AddRef, | 
|  | InPlaceFrame_Release, | 
|  | InPlaceFrame_GetWindow, | 
|  | InPlaceFrame_ContextSensitiveHelp, | 
|  | InPlaceFrame_GetBorder, | 
|  | InPlaceFrame_RequestBorderSpace, | 
|  | InPlaceFrame_SetBorderSpace, | 
|  | InPlaceUIWindow_SetActiveObject, | 
|  | }; | 
|  |  | 
|  | static IOleInPlaceFrame InPlaceUIWindow = { &InPlaceUIWindowVtbl }; | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_QueryInterface(IOleInPlaceSite *iface, REFIID riid, void **ppv) | 
|  | { | 
|  | return QueryInterface(riid, ppv); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI InPlaceSite_AddRef(IOleInPlaceSite *iface) | 
|  | { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI InPlaceSite_Release(IOleInPlaceSite *iface) | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_GetWindow(IOleInPlaceSite *iface, HWND *phwnd) | 
|  | { | 
|  | *phwnd = container_hwnd; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_ContextSensitiveHelp(IOleInPlaceSite *iface, BOOL fEnterMode) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_CanInPlaceActivate(IOleInPlaceSite *iface) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_OnInPlaceActivate(IOleInPlaceSite *iface) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_OnUIActivate(IOleInPlaceSite *iface) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_GetWindowContext(IOleInPlaceSite *iface, | 
|  | IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, | 
|  | LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) | 
|  | { | 
|  | static const RECT rect = {0,0,300,300}; | 
|  |  | 
|  | *ppFrame = &InPlaceFrame; | 
|  | *ppDoc = (IOleInPlaceUIWindow*)&InPlaceUIWindow; | 
|  | *lprcPosRect = rect; | 
|  | *lprcClipRect = rect; | 
|  |  | 
|  | lpFrameInfo->cb = sizeof(*lpFrameInfo); | 
|  | lpFrameInfo->fMDIApp = FALSE; | 
|  | lpFrameInfo->hwndFrame = container_hwnd; | 
|  | lpFrameInfo->haccel = NULL; | 
|  | lpFrameInfo->cAccelEntries = 0; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_Scroll(IOleInPlaceSite *iface, SIZE scrollExtant) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_OnUIDeactivate(IOleInPlaceSite *iface, BOOL fUndoable) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_OnInPlaceDeactivate(IOleInPlaceSite *iface) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_DiscardUndoState(IOleInPlaceSite *iface) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_DeactivateAndUndo(IOleInPlaceSite *iface) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InPlaceSite_OnPosRectChange(IOleInPlaceSite *iface, LPCRECT lprcPosRect) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IOleInPlaceSiteVtbl InPlaceSiteVtbl = { | 
|  | InPlaceSite_QueryInterface, | 
|  | InPlaceSite_AddRef, | 
|  | InPlaceSite_Release, | 
|  | InPlaceSite_GetWindow, | 
|  | InPlaceSite_ContextSensitiveHelp, | 
|  | InPlaceSite_CanInPlaceActivate, | 
|  | InPlaceSite_OnInPlaceActivate, | 
|  | InPlaceSite_OnUIActivate, | 
|  | InPlaceSite_GetWindowContext, | 
|  | InPlaceSite_Scroll, | 
|  | InPlaceSite_OnUIDeactivate, | 
|  | InPlaceSite_OnInPlaceDeactivate, | 
|  | InPlaceSite_DiscardUndoState, | 
|  | InPlaceSite_DeactivateAndUndo, | 
|  | InPlaceSite_OnPosRectChange, | 
|  | }; | 
|  |  | 
|  | static IOleInPlaceSite InPlaceSite = { &InPlaceSiteVtbl }; | 
|  |  | 
|  | static HRESULT WINAPI ClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv) | 
|  | { | 
|  | return QueryInterface(riid, ppv); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ClientSite_AddRef(IOleClientSite *iface) | 
|  | { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI ClientSite_Release(IOleClientSite *iface) | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ClientSite_SaveObject(IOleClientSite *iface) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ClientSite_GetMoniker(IOleClientSite *iface, DWORD dwAssign, DWORD dwWhichMoniker, | 
|  | IMoniker **ppmon) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ClientSite_GetContainer(IOleClientSite *iface, IOleContainer **ppContainer) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ClientSite_ShowObject(IOleClientSite *iface) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ClientSite_OnShowWindow(IOleClientSite *iface, BOOL fShow) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI ClientSite_RequestNewObjectLayout(IOleClientSite *iface) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IOleClientSiteVtbl ClientSiteVtbl = { | 
|  | ClientSite_QueryInterface, | 
|  | ClientSite_AddRef, | 
|  | ClientSite_Release, | 
|  | ClientSite_SaveObject, | 
|  | ClientSite_GetMoniker, | 
|  | ClientSite_GetContainer, | 
|  | ClientSite_ShowObject, | 
|  | ClientSite_OnShowWindow, | 
|  | ClientSite_RequestNewObjectLayout | 
|  | }; | 
|  |  | 
|  | static IOleClientSite ClientSite = { &ClientSiteVtbl }; | 
|  |  | 
|  | static HRESULT WINAPI DocumentSite_QueryInterface(IOleDocumentSite *iface, REFIID riid, void **ppv) | 
|  | { | 
|  | return QueryInterface(riid, ppv); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI DocumentSite_AddRef(IOleDocumentSite *iface) | 
|  | { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI DocumentSite_Release(IOleDocumentSite *iface) | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocumentView *pViewToActivate) | 
|  | { | 
|  | RECT rect = {0,0,300,300}; | 
|  | IOleDocument *document; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IOleDocumentView_QueryInterface(pViewToActivate, &IID_IOleDocument, (void**)&document); | 
|  | ok(hres == S_OK, "could not get IOleDocument: %08x\n", hres); | 
|  |  | 
|  | hres = IOleDocument_CreateView(document, &InPlaceSite, NULL, 0, &view); | 
|  | IOleDocument_Release(document); | 
|  | ok(hres == S_OK, "CreateView failed: %08x\n", hres); | 
|  |  | 
|  | hres = IOleDocumentView_SetInPlaceSite(view, &InPlaceSite); | 
|  | ok(hres == S_OK, "SetInPlaceSite failed: %08x\n", hres); | 
|  |  | 
|  | hres = IOleDocumentView_UIActivate(view, TRUE); | 
|  | ok(hres == S_OK, "UIActivate failed: %08x\n", hres); | 
|  |  | 
|  | hres = IOleDocumentView_SetRect(view, &rect); | 
|  | ok(hres == S_OK, "SetRect failed: %08x\n", hres); | 
|  |  | 
|  | hres = IOleDocumentView_Show(view, TRUE); | 
|  | ok(hres == S_OK, "Show failed: %08x\n", hres); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static const IOleDocumentSiteVtbl DocumentSiteVtbl = { | 
|  | DocumentSite_QueryInterface, | 
|  | DocumentSite_AddRef, | 
|  | DocumentSite_Release, | 
|  | DocumentSite_ActivateMe | 
|  | }; | 
|  |  | 
|  | static IOleDocumentSite DocumentSite = { &DocumentSiteVtbl }; | 
|  |  | 
|  | static HRESULT QueryInterface(REFIID riid, void **ppv) | 
|  | { | 
|  | *ppv = NULL; | 
|  |  | 
|  | if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IOleClientSite, riid)) | 
|  | *ppv = &ClientSite; | 
|  | else if(IsEqualGUID(&IID_IOleDocumentSite, riid)) | 
|  | *ppv = &DocumentSite; | 
|  | else if(IsEqualGUID(&IID_IOleWindow, riid) || IsEqualGUID(&IID_IOleInPlaceSite, riid)) | 
|  | *ppv = &InPlaceSite; | 
|  |  | 
|  | return *ppv ? S_OK : E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static IHTMLDocument2 *notif_doc; | 
|  | static BOOL doc_complete; | 
|  |  | 
|  | static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface, | 
|  | REFIID riid, void**ppv) | 
|  | { | 
|  | if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) { | 
|  | *ppv = iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface) | 
|  | { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface) | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID) | 
|  | { | 
|  | if(dispID == DISPID_READYSTATE){ | 
|  | BSTR state; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IHTMLDocument2_get_readyState(notif_doc, &state); | 
|  | ok(hres == S_OK, "get_readyState failed: %08x\n", hres); | 
|  |  | 
|  | if(!strcmp_wa(state, "complete")) | 
|  | doc_complete = TRUE; | 
|  |  | 
|  | SysFreeString(state); | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID) | 
|  | { | 
|  | ok(0, "unexpected call\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = { | 
|  | PropertyNotifySink_QueryInterface, | 
|  | PropertyNotifySink_AddRef, | 
|  | PropertyNotifySink_Release, | 
|  | PropertyNotifySink_OnChanged, | 
|  | PropertyNotifySink_OnRequestEdit | 
|  | }; | 
|  |  | 
|  | static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl }; | 
|  |  | 
|  | static void doc_load_string(IHTMLDocument2 *doc, const char *str) | 
|  | { | 
|  | IPersistStreamInit *init; | 
|  | IStream *stream; | 
|  | HGLOBAL mem; | 
|  | SIZE_T len; | 
|  |  | 
|  | notif_doc = doc; | 
|  |  | 
|  | doc_complete = FALSE; | 
|  | len = strlen(str); | 
|  | mem = GlobalAlloc(0, len); | 
|  | memcpy(mem, str, len); | 
|  | CreateStreamOnHGlobal(mem, TRUE, &stream); | 
|  |  | 
|  | IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init); | 
|  |  | 
|  | IPersistStreamInit_Load(init, stream); | 
|  | IPersistStreamInit_Release(init); | 
|  | IStream_Release(stream); | 
|  | } | 
|  |  | 
|  | static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise) | 
|  | { | 
|  | IConnectionPointContainer *container; | 
|  | IConnectionPoint *cp; | 
|  | DWORD cookie; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container); | 
|  | ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres); | 
|  |  | 
|  | hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp); | 
|  | IConnectionPointContainer_Release(container); | 
|  | ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres); | 
|  |  | 
|  | hres = IConnectionPoint_Advise(cp, unk_advise, &cookie); | 
|  | IConnectionPoint_Release(cp); | 
|  | ok(hres == S_OK, "Advise failed: %08x\n", hres); | 
|  | } | 
|  |  | 
|  | static void set_client_site(IHTMLDocument2 *doc, BOOL set) | 
|  | { | 
|  | IOleObject *oleobj; | 
|  | HRESULT hres; | 
|  |  | 
|  | if(!set && view) { | 
|  | IOleDocumentView_Show(view, FALSE); | 
|  | IOleDocumentView_CloseView(view, 0); | 
|  | IOleDocumentView_SetInPlaceSite(view, NULL); | 
|  | IOleDocumentView_Release(view); | 
|  | view = NULL; | 
|  | } | 
|  |  | 
|  | hres = IHTMLDocument2_QueryInterface(doc, &IID_IOleObject, (void**)&oleobj); | 
|  | ok(hres == S_OK, "Could not et IOleObject: %08x\n", hres); | 
|  |  | 
|  | hres = IOleObject_SetClientSite(oleobj, set ? &ClientSite : NULL); | 
|  | ok(hres == S_OK, "SetClientSite failed: %08x\n", hres); | 
|  |  | 
|  | if(set) { | 
|  | IHlinkTarget *hlink; | 
|  |  | 
|  | hres = IOleObject_QueryInterface(oleobj, &IID_IHlinkTarget, (void**)&hlink); | 
|  | ok(hres == S_OK, "Could not get IHlinkTarget iface: %08x\n", hres); | 
|  |  | 
|  | hres = IHlinkTarget_Navigate(hlink, 0, NULL); | 
|  | ok(hres == S_OK, "Navgate failed: %08x\n", hres); | 
|  |  | 
|  | IHlinkTarget_Release(hlink); | 
|  | } | 
|  |  | 
|  | IOleObject_Release(oleobj); | 
|  | } | 
|  | static IHTMLDocument2 *create_document(void) | 
|  | { | 
|  | IHTMLDocument2 *doc; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, | 
|  | &IID_IHTMLDocument2, (void**)&doc); | 
|  | ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); | 
|  |  | 
|  | return doc; | 
|  | } | 
|  |  | 
|  |  | 
|  | typedef void (*testfunc_t)(IHTMLDocument2*); | 
|  |  | 
|  | static void run_test(const char *str, testfunc_t test) | 
|  | { | 
|  | IHTMLDocument2 *doc; | 
|  | IHTMLElement *body = NULL; | 
|  | ULONG ref; | 
|  | MSG msg; | 
|  | HRESULT hres; | 
|  |  | 
|  | doc = create_document(); | 
|  | set_client_site(doc, TRUE); | 
|  | doc_load_string(doc, str); | 
|  | do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink); | 
|  |  | 
|  | while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) { | 
|  | TranslateMessage(&msg); | 
|  | DispatchMessage(&msg); | 
|  | } | 
|  |  | 
|  | hres = IHTMLDocument2_get_body(doc, &body); | 
|  | ok(hres == S_OK, "get_body failed: %08x\n", hres); | 
|  |  | 
|  | if(body) { | 
|  | IHTMLElement_Release(body); | 
|  |  | 
|  | hres = IHTMLDocument2_get_parentWindow(doc, &window); | 
|  | ok(hres == S_OK, "get_parentWindow failed: %08x\n", hres); | 
|  | ok(window != NULL, "window == NULL\n"); | 
|  |  | 
|  | test(doc); | 
|  |  | 
|  | IHTMLWindow2_Release(window); | 
|  | window = NULL; | 
|  | }else { | 
|  | skip("Could not get document body. Assuming no Gecko installed.\n"); | 
|  | } | 
|  |  | 
|  | set_client_site(doc, FALSE); | 
|  | ref = IHTMLDocument2_Release(doc); | 
|  | ok(!ref, "ref = %d\n", ref); | 
|  | } | 
|  |  | 
|  | static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | return DefWindowProc(hwnd, msg, wParam, lParam); | 
|  | } | 
|  |  | 
|  | static HWND create_container_window(void) | 
|  | { | 
|  | static const CHAR szHTMLDocumentTest[] = "HTMLDocumentTest"; | 
|  | static WNDCLASSEXA wndclass = { | 
|  | sizeof(WNDCLASSEXA), | 
|  | 0, | 
|  | wnd_proc, | 
|  | 0, 0, NULL, NULL, NULL, NULL, NULL, | 
|  | szHTMLDocumentTest, | 
|  | NULL | 
|  | }; | 
|  |  | 
|  | RegisterClassExA(&wndclass); | 
|  | return CreateWindowA(szHTMLDocumentTest, szHTMLDocumentTest, | 
|  | WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, | 
|  | 300, 300, NULL, NULL, NULL, NULL); | 
|  | } | 
|  |  | 
|  | START_TEST(events) | 
|  | { | 
|  | CoInitialize(NULL); | 
|  | container_hwnd = create_container_window(); | 
|  |  | 
|  | if(winetest_interactive) | 
|  | ShowWindow(container_hwnd, SW_SHOW); | 
|  |  | 
|  | run_test(empty_doc_str, test_timeout); | 
|  | run_test(click_doc_str, test_onclick); | 
|  |  | 
|  | DestroyWindow(container_hwnd); | 
|  | CoUninitialize(); | 
|  | } |