/* * 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 #include #include #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; static BOOL xy_todo; 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[] = ""; static const char click_doc_str[] = "" "
click here
" ""; 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 get_elem3_iface(u) _get_elem3_iface(__LINE__,u) static IHTMLElement3 *_get_elem3_iface(unsigned line, IUnknown *unk) { IHTMLElement3 *elem3; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement3, (void**)&elem3); ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElement3 iface: %08x\n", hres); return elem3; } #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 elem_fire_event(a,b,c) _elem_fire_event(__LINE__,a,b,c) static void _elem_fire_event(unsigned line, IUnknown *unk, const char *event, VARIANT *evobj) { IHTMLElement3 *elem3 = _get_elem3_iface(line, unk); VARIANT_BOOL b; BSTR str; HRESULT hres; b = 100; str = a2bstr(event); hres = IHTMLElement3_fireEvent(elem3, str, evobj, &b); SysFreeString(str); ok_(__FILE__,line)(hres == S_OK, "fireEvent failed: %08x\n", hres); ok_(__FILE__,line)(b == VARIANT_TRUE, "fireEvent returned %x\n", b); } #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 */ if(xy_todo) todo_wine ok_(__FILE__,line)(l > 0, "clientX = %d\n", l); else 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 */ if(xy_todo) todo_wine ok_(__FILE__,line)(l > 0, "clientY = %d\n", l); else 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 */ if(xy_todo) todo_wine ok_(__FILE__,line)(l > 0, "screenX = %d\n", l); else 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 */ if(xy_todo) todo_wine ok_(__FILE__,line)(l > 0, "screenY = %d\n", l); else 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); } xy_todo = TRUE; SET_EXPECT(div_onclick); SET_EXPECT(div_onclick_attached); SET_EXPECT(body_onclick); SET_EXPECT(document_onclick); hres = IHTMLElement_click(div); ok(hres == S_OK, "click failed: %08x\n", hres); CHECK_CALLED(div_onclick); CHECK_CALLED(div_onclick_attached); CHECK_CALLED(body_onclick); CHECK_CALLED(document_onclick); SET_EXPECT(div_onclick); SET_EXPECT(div_onclick_attached); SET_EXPECT(body_onclick); SET_EXPECT(document_onclick); V_VT(&v) = VT_EMPTY; elem_fire_event((IUnknown*)div, "onclick", &v); 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; xy_todo = FALSE; 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(); }