/* * Copyright 2007-2008 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 "mshtmcid.h" #include "mshtmhst.h" #include "docobj.h" #include "dispex.h" static const char doc_blank[] = ""; static const char doc_str1[] = "test"; static const char range_test_str[] = "test \nabc\t123
it's\r\n \t
text
"; static const char range_test2_str[] = "abc
123

def"; static const char elem_test_str[] = "test" "text test" "link" "" "" "" "
td1 texttd2 text
" "" "" "" "" ""; static const char indent_test_str[] = "testabc
123"; static const char cond_comment_str[] = "test" "" ""; static const WCHAR noneW[] = {'N','o','n','e',0}; static WCHAR characterW[] = {'c','h','a','r','a','c','t','e','r',0}; static WCHAR texteditW[] = {'t','e','x','t','e','d','i','t',0}; static WCHAR wordW[] = {'w','o','r','d',0}; static const WCHAR text_javascriptW[] = {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0}; static const WCHAR idW[] = {'i','d',0}; typedef enum { ET_NONE, ET_HTML, ET_HEAD, ET_TITLE, ET_BODY, ET_A, ET_INPUT, ET_SELECT, ET_TEXTAREA, ET_OPTION, ET_STYLE, ET_BLOCKQUOTE, ET_P, ET_BR, ET_TABLE, ET_TBODY, ET_SCRIPT, ET_TEST, ET_TESTG, ET_COMMENT, ET_IMG, ET_TR, ET_TD, ET_IFRAME } elem_type_t; static const IID * const none_iids[] = { &IID_IUnknown, NULL }; static const IID * const elem_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const body_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLTextContainer, &IID_IHTMLBodyElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const anchor_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLAnchorElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const input_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLInputElement, &IID_IHTMLInputTextElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const select_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLSelectElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const textarea_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLTextAreaElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const option_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLOptionElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const table_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLTable, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const script_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLScriptElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const text_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLDOMTextNode, NULL }; static const IID * const location_iids[] = { &IID_IDispatch, &IID_IHTMLLocation, NULL }; static const IID * const window_iids[] = { &IID_IDispatch, &IID_IHTMLWindow2, &IID_IHTMLWindow3, &IID_IDispatchEx, NULL }; static const IID * const comment_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLCommentElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const img_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IDispatchEx, &IID_IHTMLImgElement, &IID_IConnectionPointContainer, NULL }; static const IID * const tr_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IDispatchEx, &IID_IHTMLTableRow, &IID_IConnectionPointContainer, NULL }; static const IID * const td_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const iframe_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLFrameBase2, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const generic_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, &IID_IHTMLElement3, &IID_IHTMLGenericElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; static const IID * const style_iids[] = { &IID_IUnknown, &IID_IDispatch, &IID_IDispatchEx, &IID_IHTMLStyle, &IID_IHTMLStyle2, &IID_IHTMLStyle3, &IID_IHTMLStyle4, NULL }; static const IID * const cstyle_iids[] = { &IID_IUnknown, &IID_IDispatch, &IID_IDispatchEx, &IID_IHTMLCurrentStyle, NULL }; typedef struct { const char *tag; REFIID *iids; const IID *dispiid; } elem_type_info_t; static const elem_type_info_t elem_type_infos[] = { {"", none_iids, NULL}, {"HTML", elem_iids, NULL}, {"HEAD", elem_iids, NULL}, {"TITLE", elem_iids, NULL}, {"BODY", body_iids, &DIID_DispHTMLBody}, {"A", anchor_iids, NULL}, {"INPUT", input_iids, &DIID_DispHTMLInputElement}, {"SELECT", select_iids, &DIID_DispHTMLSelectElement}, {"TEXTAREA", textarea_iids, NULL}, {"OPTION", option_iids, &DIID_DispHTMLOptionElement}, {"STYLE", elem_iids, NULL}, {"BLOCKQUOTE",elem_iids, NULL}, {"P", elem_iids, NULL}, {"BR", elem_iids, NULL}, {"TABLE", table_iids, &DIID_DispHTMLTable}, {"TBODY", elem_iids, NULL}, {"SCRIPT", script_iids, NULL}, {"TEST", elem_iids, &DIID_DispHTMLUnknownElement}, {"TEST", generic_iids, &DIID_DispHTMLGenericElement}, {"!", comment_iids, &DIID_DispHTMLCommentElement}, {"IMG", img_iids, &DIID_DispHTMLImg}, {"TR", tr_iids, &DIID_DispHTMLTableRow}, {"TD", td_iids, NULL}, {"IFRAME", iframe_iids, &DIID_DispHTMLIFrame} }; static const char *dbgstr_w(LPCWSTR str) { static char buf[512]; if(!str) return "(null)"; WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL); return buf; } static const char *dbgstr_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) { WCHAR buf[512]; MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR)); return lstrcmpW(strw, buf); } static BSTR a2bstr(const char *str) { BSTR ret; int len; len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); ret = SysAllocStringLen(NULL, len); 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; } static IHTMLDocument2 *create_document(void) { IHTMLDocument2 *doc; IHTMLDocument5 *doc5; 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); hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument5, (void**)&doc5); if(FAILED(hres)) { win_skip("Could not get IHTMLDocument5, probably too old IE\n"); IHTMLDocument2_Release(doc); return NULL; } IHTMLDocument5_Release(doc5); return doc; } #define test_ifaces(i,ids) _test_ifaces(__LINE__,i,ids) static void _test_ifaces(unsigned line, IUnknown *iface, REFIID *iids) { const IID * const *piid; IUnknown *unk; HRESULT hres; for(piid = iids; *piid; piid++) { hres = IDispatch_QueryInterface(iface, *piid, (void**)&unk); ok_(__FILE__,line) (hres == S_OK, "Could not get %s interface: %08x\n", dbgstr_guid(*piid), hres); if(SUCCEEDED(hres)) IUnknown_Release(unk); } } #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", dbgstr_guid(&type_attr->guid)); ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr); ITypeInfo_Release(typeinfo); } IDispatchEx_Release(dispex); } #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, "Coule not get IHTMLElement: %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 *elem; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement2, (void**)&elem); ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLElement2: %08x\n", hres); return elem; } #define get_elem3_iface(u) _get_elem3_iface(__LINE__,u) static IHTMLElement3 *_get_elem3_iface(unsigned line, IUnknown *unk) { IHTMLElement3 *elem; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement3, (void**)&elem); ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLElement3: %08x\n", hres); return elem; } #define get_node_iface(u) _get_node_iface(__LINE__,u) static IHTMLDOMNode *_get_node_iface(unsigned line, IUnknown *unk) { IHTMLDOMNode *node; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode, (void**)&node); ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLDOMNode: %08x\n", hres); return node; } #define get_img_iface(u) _get_img_iface(__LINE__,u) static IHTMLImgElement *_get_img_iface(unsigned line, IUnknown *unk) { IHTMLImgElement *img; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLImgElement, (void**)&img); ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLImgElement: %08x\n", hres); return img; } #define test_node_name(u,n) _test_node_name(__LINE__,u,n) static void _test_node_name(unsigned line, IUnknown *unk, const char *exname) { IHTMLDOMNode *node = _get_node_iface(line, unk); BSTR name; HRESULT hres; hres = IHTMLDOMNode_get_nodeName(node, &name); IHTMLDOMNode_Release(node); ok_(__FILE__, line) (hres == S_OK, "get_nodeName failed: %08x\n", hres); ok_(__FILE__, line) (!strcmp_wa(name, exname), "got name: %s, expected %s\n", dbgstr_w(name), exname); SysFreeString(name); } #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", dbgstr_w(tag), extag); SysFreeString(tag); } #define test_elem_type(ifc,t) _test_elem_type(__LINE__,ifc,t) static void _test_elem_type(unsigned line, IUnknown *unk, elem_type_t type) { _test_elem_tag(line, unk, elem_type_infos[type].tag); _test_ifaces(line, unk, elem_type_infos[type].iids); if(elem_type_infos[type].dispiid) _test_disp(line, unk, elem_type_infos[type].dispiid); } #define get_node_type(n) _get_node_type(__LINE__,n) static long _get_node_type(unsigned line, IUnknown *unk) { IHTMLDOMNode *node = _get_node_iface(line, unk); long type = -1; HRESULT hres; hres = IHTMLDOMNode_get_nodeType(node, &type); ok(hres == S_OK, "get_nodeType failed: %08x\n", hres); IHTMLDOMNode_Release(node); return type; } #define get_child_nodes(u) _get_child_nodes(__LINE__,u) static IHTMLDOMChildrenCollection *_get_child_nodes(unsigned line, IUnknown *unk) { IHTMLDOMNode *node = _get_node_iface(line, unk); IHTMLDOMChildrenCollection *col = NULL; IDispatch *disp; HRESULT hres; hres = IHTMLDOMNode_get_childNodes(node, &disp); IHTMLDOMNode_Release(node); ok_(__FILE__,line) (hres == S_OK, "get_childNodes failed: %08x\n", hres); if(FAILED(hres)) return NULL; hres = IDispatch_QueryInterface(disp, &IID_IHTMLDOMChildrenCollection, (void**)&col); IDispatch_Release(disp); ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDOMChildrenCollection: %08x\n", hres); return col; } #define get_child_item(c,i) _get_child_item(__LINE__,c,i) static IHTMLDOMNode *_get_child_item(unsigned line, IHTMLDOMChildrenCollection *col, long idx) { IHTMLDOMNode *node = NULL; IDispatch *disp; HRESULT hres; hres = IHTMLDOMChildrenCollection_item(col, idx, &disp); ok(hres == S_OK, "item failed: %08x\n", hres); node = _get_node_iface(line, (IUnknown*)disp); IDispatch_Release(disp); return node; } #define test_elem_attr(e,n,v) _test_elem_attr(__LINE__,e,n,v) static void _test_elem_attr(unsigned line, IHTMLElement *elem, LPCWSTR name, LPCWSTR exval) { VARIANT value; BSTR tmp; HRESULT hres; VariantInit(&value); tmp = SysAllocString(name); hres = IHTMLElement_getAttribute(elem, tmp, 0, &value); SysFreeString(tmp); ok_(__FILE__,line) (hres == S_OK, "getAttribute failed: %08x\n", hres); if(exval) { ok_(__FILE__,line) (V_VT(&value) == VT_BSTR, "vt=%d\n", V_VT(&value)); ok_(__FILE__,line) (!lstrcmpW(exval, V_BSTR(&value)), "unexpected value %s\n", dbgstr_w(V_BSTR(&value))); }else { ok_(__FILE__,line) (V_VT(&value) == VT_NULL, "vt=%d\n", V_VT(&value)); } VariantClear(&value); } #define test_elem_offset(u) _test_elem_offset(__LINE__,u) static void _test_elem_offset(unsigned line, IUnknown *unk) { IHTMLElement *elem = _get_elem_iface(line, unk); long l; HRESULT hres; hres = IHTMLElement_get_offsetTop(elem, &l); ok_(__FILE__,line) (hres == S_OK, "get_offsetTop failed: %08x\n", hres); hres = IHTMLElement_get_offsetHeight(elem, &l); ok_(__FILE__,line) (hres == S_OK, "get_offsetHeight failed: %08x\n", hres); hres = IHTMLElement_get_offsetWidth(elem, &l); ok_(__FILE__,line) (hres == S_OK, "get_offsetWidth failed: %08x\n", hres); IHTMLElement_Release(elem); } static void test_doc_elem(IHTMLDocument2 *doc) { IHTMLElement *elem; IHTMLDocument3 *doc3; HRESULT hres; hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3); ok(hres == S_OK, "QueryInterface(IID_IHTMLDocument3) failed: %08x\n", hres); hres = IHTMLDocument3_get_documentElement(doc3, &elem); IHTMLDocument3_Release(doc3); ok(hres == S_OK, "get_documentElement failed: %08x\n", hres); test_node_name((IUnknown*)elem, "HTML"); test_elem_tag((IUnknown*)elem, "HTML"); IHTMLElement_Release(elem); } #define get_doc_elem(d) _get_doc_elem(__LINE__,d) static IHTMLElement *_get_doc_elem(unsigned line, IHTMLDocument2 *doc) { IHTMLElement *elem; IHTMLDocument3 *doc3; HRESULT hres; hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3); ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDocument3 interface: %08x\n", hres); hres = IHTMLDocument3_get_documentElement(doc3, &elem); ok_(__FILE__,line) (hres == S_OK, "get_documentElement failed: %08x\n", hres); IHTMLDocument3_Release(doc3); return elem; } #define test_option_text(o,t) _test_option_text(__LINE__,o,t) static void _test_option_text(unsigned line, IHTMLOptionElement *option, const char *text) { BSTR bstr; HRESULT hres; hres = IHTMLOptionElement_get_text(option, &bstr); ok_(__FILE__,line) (hres == S_OK, "get_text failed: %08x\n", hres); ok_(__FILE__,line) (!strcmp_wa(bstr, text), "text=%s\n", dbgstr_w(bstr)); SysFreeString(bstr); } #define test_option_put_text(o,t) _test_option_put_text(__LINE__,o,t) static void _test_option_put_text(unsigned line, IHTMLOptionElement *option, const char *text) { BSTR bstr; HRESULT hres; bstr = a2bstr(text); hres = IHTMLOptionElement_put_text(option, bstr); SysFreeString(bstr); ok(hres == S_OK, "put_text failed: %08x\n", hres); _test_option_text(line, option, text); } #define test_option_value(o,t) _test_option_value(__LINE__,o,t) static void _test_option_value(unsigned line, IHTMLOptionElement *option, const char *value) { BSTR bstr; HRESULT hres; hres = IHTMLOptionElement_get_value(option, &bstr); ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres); ok_(__FILE__,line) (!strcmp_wa(bstr, value), "value=%s\n", dbgstr_w(bstr)); SysFreeString(bstr); } #define test_option_put_value(o,t) _test_option_put_value(__LINE__,o,t) static void _test_option_put_value(unsigned line, IHTMLOptionElement *option, const char *value) { BSTR bstr; HRESULT hres; bstr = a2bstr(value); hres = IHTMLOptionElement_put_value(option, bstr); SysFreeString(bstr); ok(hres == S_OK, "put_value failed: %08x\n", hres); _test_option_value(line, option, value); } #define create_option_elem(d,t,v) _create_option_elem(__LINE__,d,t,v) static IHTMLOptionElement *_create_option_elem(unsigned line, IHTMLDocument2 *doc, const char *txt, const char *val) { IHTMLOptionElementFactory *factory; IHTMLOptionElement *option; IHTMLWindow2 *window; VARIANT text, value, empty; HRESULT hres; hres = IHTMLDocument2_get_parentWindow(doc, &window); ok_(__FILE__,line) (hres == S_OK, "get_parentElement failed: %08x\n", hres); hres = IHTMLWindow2_get_Option(window, &factory); IHTMLWindow2_Release(window); ok_(__FILE__,line) (hres == S_OK, "get_Option failed: %08x\n", hres); V_VT(&text) = VT_BSTR; V_BSTR(&text) = a2bstr(txt); V_VT(&value) = VT_BSTR; V_BSTR(&value) = a2bstr(val); V_VT(&empty) = VT_EMPTY; hres = IHTMLOptionElementFactory_create(factory, text, value, empty, empty, &option); ok_(__FILE__,line) (hres == S_OK, "create failed: %08x\n", hres); IHTMLOptionElementFactory_Release(factory); VariantClear(&text); VariantClear(&value); _test_option_text(line, option, txt); _test_option_value(line, option, val); return option; } #define test_select_length(s,l) _test_select_length(__LINE__,s,l) static void _test_select_length(unsigned line, IHTMLSelectElement *select, long length) { long len = 0xdeadbeef; HRESULT hres; hres = IHTMLSelectElement_get_length(select, &len); ok_(__FILE__,line) (hres == S_OK, "get_length failed: %08x\n", hres); ok_(__FILE__,line) (len == length, "len=%ld, expected %ld\n", len, length); } #define test_select_selidx(s,i) _test_select_selidx(__LINE__,s,i) static void _test_select_selidx(unsigned line, IHTMLSelectElement *select, long index) { long idx = 0xdeadbeef; HRESULT hres; hres = IHTMLSelectElement_get_selectedIndex(select, &idx); ok_(__FILE__,line) (hres == S_OK, "get_selectedIndex failed: %08x\n", hres); ok_(__FILE__,line) (idx == index, "idx=%ld, expected %ld\n", idx, index); } #define test_select_put_selidx(s,i) _test_select_put_selidx(__LINE__,s,i) static void _test_select_put_selidx(unsigned line, IHTMLSelectElement *select, long index) { HRESULT hres; hres = IHTMLSelectElement_put_selectedIndex(select, index); ok_(__FILE__,line) (hres == S_OK, "get_selectedIndex failed: %08x\n", hres); _test_select_selidx(line, select, index); } #define test_select_value(s,v) _test_select_value(__LINE__,s,v) static void _test_select_value(unsigned line, IHTMLSelectElement *select, const char *exval) { BSTR val; HRESULT hres; hres = IHTMLSelectElement_get_value(select, &val); ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres); if(exval) ok_(__FILE__,line) (!strcmp_wa(val, exval), "unexpected value %s\n", dbgstr_w(val)); else ok_(__FILE__,line) (val == NULL, "val=%s, expected NULL\n", dbgstr_w(val)); } #define test_select_set_value(s,v) _test_select_set_value(__LINE__,s,v) static void _test_select_set_value(unsigned line, IHTMLSelectElement *select, const char *val) { BSTR bstr; HRESULT hres; bstr = a2bstr(val); hres = IHTMLSelectElement_put_value(select, bstr); SysFreeString(bstr); ok_(__FILE__,line) (hres == S_OK, "put_value failed: %08x\n", hres); } #define test_select_type(s,t) _test_select_type(__LINE__,s,t) static void _test_select_type(unsigned line, IHTMLSelectElement *select, const char *extype) { BSTR type; HRESULT hres; hres = IHTMLSelectElement_get_type(select, &type); ok_(__FILE__,line) (hres == S_OK, "get_type failed: %08x\n", hres); ok_(__FILE__,line) (!strcmp_wa(type, extype), "type=%s, expected %s\n", dbgstr_w(type), extype); } #define test_range_text(r,t) _test_range_text(__LINE__,r,t) static void _test_range_text(unsigned line, IHTMLTxtRange *range, const char *extext) { BSTR text; HRESULT hres; hres = IHTMLTxtRange_get_text(range, &text); ok_(__FILE__, line) (hres == S_OK, "get_text failed: %08x\n", hres); if(extext) { ok_(__FILE__, line) (text != NULL, "text == NULL\n"); ok_(__FILE__, line) (!strcmp_wa(text, extext), "text=\"%s\", expected \"%s\"\n", dbgstr_w(text), extext); }else { ok_(__FILE__, line) (text == NULL, "text=\"%s\", expected NULL\n", dbgstr_w(text)); } SysFreeString(text); } #define test_range_collapse(r,b) _test_range_collapse(__LINE__,r,b) static void _test_range_collapse(unsigned line, IHTMLTxtRange *range, BOOL b) { HRESULT hres; hres = IHTMLTxtRange_collapse(range, b); ok_(__FILE__, line) (hres == S_OK, "collapse failed: %08x\n", hres); _test_range_text(line, range, NULL); } #define test_range_expand(r,u,b,t) _test_range_expand(__LINE__,r,u,b,t) static void _test_range_expand(unsigned line, IHTMLTxtRange *range, LPWSTR unit, VARIANT_BOOL exb, const char *extext) { VARIANT_BOOL b = 0xe0e0; HRESULT hres; hres = IHTMLTxtRange_expand(range, unit, &b); ok_(__FILE__,line) (hres == S_OK, "expand failed: %08x\n", hres); ok_(__FILE__,line) (b == exb, "b=%x, expected %x\n", b, exb); _test_range_text(line, range, extext); } #define test_range_move(r,u,c,e) _test_range_move(__LINE__,r,u,c,e) static void _test_range_move(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt) { long c = 0xdeadbeef; HRESULT hres; hres = IHTMLTxtRange_move(range, unit, cnt, &c); ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres); ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt); _test_range_text(line, range, NULL); } #define test_range_movestart(r,u,c,e) _test_range_movestart(__LINE__,r,u,c,e) static void _test_range_movestart(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt) { long c = 0xdeadbeef; HRESULT hres; hres = IHTMLTxtRange_moveStart(range, unit, cnt, &c); ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres); ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt); } #define test_range_moveend(r,u,c,e) _test_range_moveend(__LINE__,r,u,c,e) static void _test_range_moveend(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt) { long c = 0xdeadbeef; HRESULT hres; hres = IHTMLTxtRange_moveEnd(range, unit, cnt, &c); ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres); ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt); } #define test_range_put_text(r,t) _test_range_put_text(__LINE__,r,t) static void _test_range_put_text(unsigned line, IHTMLTxtRange *range, const char *text) { HRESULT hres; BSTR bstr = a2bstr(text); hres = IHTMLTxtRange_put_text(range, bstr); ok_(__FILE__,line) (hres == S_OK, "put_text failed: %08x\n", hres); SysFreeString(bstr); _test_range_text(line, range, NULL); } #define test_range_inrange(r1,r2,b) _test_range_inrange(__LINE__,r1,r2,b) static void _test_range_inrange(unsigned line, IHTMLTxtRange *range1, IHTMLTxtRange *range2, VARIANT_BOOL exb) { VARIANT_BOOL b; HRESULT hres; b = 0xe0e0; hres = IHTMLTxtRange_inRange(range1, range2, &b); ok_(__FILE__,line) (hres == S_OK, "(1->2) isEqual failed: %08x\n", hres); ok_(__FILE__,line) (b == exb, "(1->2) b=%x, expected %x\n", b, exb); } #define test_range_isequal(r1,r2,b) _test_range_isequal(__LINE__,r1,r2,b) static void _test_range_isequal(unsigned line, IHTMLTxtRange *range1, IHTMLTxtRange *range2, VARIANT_BOOL exb) { VARIANT_BOOL b; HRESULT hres; b = 0xe0e0; hres = IHTMLTxtRange_isEqual(range1, range2, &b); ok_(__FILE__,line) (hres == S_OK, "(1->2) isEqual failed: %08x\n", hres); ok_(__FILE__,line) (b == exb, "(1->2) b=%x, expected %x\n", b, exb); b = 0xe0e0; hres = IHTMLTxtRange_isEqual(range2, range1, &b); ok_(__FILE__,line) (hres == S_OK, "(2->1) isEqual failed: %08x\n", hres); ok_(__FILE__,line) (b == exb, "(2->1) b=%x, expected %x\n", b, exb); if(exb) { test_range_inrange(range1, range2, VARIANT_TRUE); test_range_inrange(range2, range1, VARIANT_TRUE); } } #define test_range_parent(r,t) _test_range_parent(__LINE__,r,t) static void _test_range_parent(unsigned line, IHTMLTxtRange *range, elem_type_t type) { IHTMLElement *elem; HRESULT hres; hres = IHTMLTxtRange_parentElement(range, &elem); ok_(__FILE__,line) (hres == S_OK, "parentElement failed: %08x\n", hres); _test_elem_type(line, (IUnknown*)elem, type); IHTMLElement_Release(elem); } #define test_elem_collection(c,t,l) _test_elem_collection(__LINE__,c,t,l) static void _test_elem_collection(unsigned line, IUnknown *unk, const elem_type_t *elem_types, long exlen) { IHTMLElementCollection *col; long len; DWORD i; VARIANT name, index; IDispatch *disp; HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLElementCollection, (void**)&col); ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); test_disp((IUnknown*)col, &DIID_DispHTMLElementCollection); hres = IHTMLElementCollection_get_length(col, &len); ok_(__FILE__,line) (hres == S_OK, "get_length failed: %08x\n", hres); ok_(__FILE__,line) (len == exlen, "len=%ld, expected %ld\n", len, exlen); if(len > exlen) len = exlen; V_VT(&index) = VT_EMPTY; V_VT(&name) = VT_I4; for(i=0; itest
"); hres = IHTMLDocument2_get_all(content_doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); IHTMLElementCollection_Release(col); hres = IHTMLDocument2_close(content_doc); ok(hres == S_OK, "close failed: %08x\n", hres); IHTMLDocument2_Release(content_doc); } static void test_stylesheet(IDispatch *disp) { IHTMLStyleSheetRulesCollection *col = NULL; IHTMLStyleSheet *stylesheet; HRESULT hres; hres = IDispatch_QueryInterface(disp, &IID_IHTMLStyleSheet, (void**)&stylesheet); ok(hres == S_OK, "Could not get IHTMLStyleSheet: %08x\n", hres); hres = IHTMLStyleSheet_get_rules(stylesheet, &col); ok(hres == S_OK, "get_rules failed: %08x\n", hres); ok(col != NULL, "col == NULL\n"); IHTMLStyleSheetRulesCollection_Release(col); IHTMLStyleSheet_Release(stylesheet); } static void test_stylesheets(IHTMLDocument2 *doc) { IHTMLStyleSheetsCollection *col = NULL; VARIANT idx, res; long len = 0; HRESULT hres; hres = IHTMLDocument2_get_styleSheets(doc, &col); ok(hres == S_OK, "get_styleSheets failed: %08x\n", hres); ok(col != NULL, "col == NULL\n"); hres = IHTMLStyleSheetsCollection_get_length(col, &len); ok(hres == S_OK, "get_length failed: %08x\n", hres); ok(len == 1, "len=%ld\n", len); VariantInit(&res); V_VT(&idx) = VT_I4; V_I4(&idx) = 0; hres = IHTMLStyleSheetsCollection_item(col, &idx, &res); ok(hres == S_OK, "item failed: %08x\n", hres); ok(V_VT(&res) == VT_DISPATCH, "V_VT(res) = %d\n", V_VT(&res)); ok(V_DISPATCH(&res) != NULL, "V_DISPATCH(&res) == NULL\n"); test_stylesheet(V_DISPATCH(&res)); VariantClear(&res); V_VT(&res) = VT_I4; V_VT(&idx) = VT_I4; V_I4(&idx) = 1; hres = IHTMLStyleSheetsCollection_item(col, &idx, &res); ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); ok(V_VT(&res) == VT_EMPTY, "V_VT(res) = %d\n", V_VT(&res)); ok(V_DISPATCH(&res) != NULL, "V_DISPATCH(&res) == NULL\n"); VariantClear(&res); IHTMLStyleSheetsCollection_Release(col); } static void test_child_col_disp(IHTMLDOMChildrenCollection *col) { IDispatchEx *dispex; IHTMLDOMNode *node; DISPPARAMS dp = {NULL, NULL, 0, 0}; VARIANT var; EXCEPINFO ei; long type; DISPID id; BSTR bstr; HRESULT hres; static const WCHAR w0[] = {'0',0}; static const WCHAR w100[] = {'1','0','0',0}; hres = IHTMLDOMChildrenCollection_QueryInterface(col, &IID_IDispatchEx, (void**)&dispex); ok(hres == S_OK, "Could not get IDispatchEx: %08x\n", hres); bstr = SysAllocString(w0); hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id); ok(hres == S_OK, "GetDispID failed: %08x\n", hres); SysFreeString(bstr); VariantInit(&var); hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL); ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var)); ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n"); node = get_node_iface((IUnknown*)V_DISPATCH(&var)); type = get_node_type((IUnknown*)node); ok(type == 3, "type=%ld\n", type); IHTMLDOMNode_Release(node); VariantClear(&var); bstr = SysAllocString(w100); hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id); ok(hres == DISP_E_UNKNOWNNAME, "GetDispID failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres); SysFreeString(bstr); IDispatchEx_Release(dispex); } static void test_elems(IHTMLDocument2 *doc) { IHTMLElementCollection *col; IHTMLDOMChildrenCollection *child_col; IHTMLElement *elem, *elem2, *elem3; IHTMLDOMNode *node, *node2; IDispatch *disp; long type; HRESULT hres; IHTMLElementCollection *collection; IHTMLDocument3 *doc3; BSTR str; static const WCHAR imgidW[] = {'i','m','g','i','d',0}; static const WCHAR inW[] = {'i','n',0}; static const WCHAR xW[] = {'x',0}; static const WCHAR sW[] = {'s',0}; static const WCHAR scW[] = {'s','c',0}; static const WCHAR xxxW[] = {'x','x','x',0}; static const WCHAR tblW[] = {'t','b','l',0}; static const WCHAR row2W[] = {'r','o','w','2',0}; static const WCHAR ifrW[] = {'i','f','r',0}; static const elem_type_t all_types[] = { ET_HTML, ET_HEAD, ET_TITLE, ET_STYLE, ET_BODY, ET_COMMENT, ET_A, ET_INPUT, ET_SELECT, ET_OPTION, ET_OPTION, ET_TEXTAREA, ET_TABLE, ET_TBODY, ET_TR, ET_TR, ET_TD, ET_TD, ET_SCRIPT, ET_TEST, ET_IMG, ET_IFRAME }; static const elem_type_t item_types[] = { ET_A, ET_OPTION, ET_TEXTAREA }; hres = IHTMLDocument2_get_all(doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); test_elem_col_item(col, xW, item_types, sizeof(item_types)/sizeof(item_types[0])); IHTMLElementCollection_Release(col); hres = IHTMLDocument2_get_images(doc, &collection); ok(hres == S_OK, "get_images failed: %08x\n", hres); if(hres == S_OK) { static const elem_type_t images_types[] = {ET_IMG}; test_elem_collection((IUnknown*)collection, images_types, 1); IHTMLElementCollection_Release(collection); } hres = IHTMLDocument2_get_links(doc, &collection); ok(hres == S_OK, "get_links failed: %08x\n", hres); if(hres == S_OK) { static const elem_type_t images_types[] = {ET_A}; test_elem_collection((IUnknown*)collection, images_types, 1); IHTMLElementCollection_Release(collection); } hres = IHTMLDocument2_get_anchors(doc, &collection); ok(hres == S_OK, "get_anchors failed: %08x\n", hres); if(hres == S_OK) { static const elem_type_t anchor_types[] = {ET_A}; test_elem_collection((IUnknown*)collection, anchor_types, 1); IHTMLElementCollection_Release(collection); } elem = get_doc_elem(doc); ok(hres == S_OK, "get_documentElement failed: %08x\n", hres); hres = IHTMLElement_get_all(elem, &disp); IHTMLElement_Release(elem); ok(hres == S_OK, "get_all failed: %08x\n", hres); hres = IDispatch_QueryInterface(disp, &IID_IHTMLElementCollection, (void**)&col); IDispatch_Release(disp); ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); test_elem_collection((IUnknown*)col, all_types+1, sizeof(all_types)/sizeof(all_types[0])-1); IHTMLElementCollection_Release(col); get_elem_by_id(doc, xxxW, FALSE); elem = get_doc_elem_by_id(doc, xxxW); ok(!elem, "elem != NULL\n"); elem = get_doc_elem_by_id(doc, sW); ok(elem != NULL, "elem == NULL\n"); if(elem) { test_elem_type((IUnknown*)elem, ET_SELECT); test_elem_attr(elem, xxxW, NULL); test_elem_attr(elem, idW, sW); test_elem_class((IUnknown*)elem, NULL); test_elem_set_class((IUnknown*)elem, "cl"); test_elem_set_class((IUnknown*)elem, NULL); test_elem_tabindex((IUnknown*)elem, 0); test_elem_set_tabindex((IUnknown*)elem, 1); node = test_node_get_parent((IUnknown*)elem); ok(node != NULL, "node == NULL\n"); test_node_name((IUnknown*)node, "BODY"); node2 = test_node_get_parent((IUnknown*)node); IHTMLDOMNode_Release(node); ok(node2 != NULL, "node == NULL\n"); test_node_name((IUnknown*)node2, "HTML"); node = test_node_get_parent((IUnknown*)node2); IHTMLDOMNode_Release(node2); ok(node != NULL, "node == NULL\n"); if (node) { test_node_name((IUnknown*)node, "#document"); type = get_node_type((IUnknown*)node); ok(type == 9, "type=%ld, expected 9\n", type); node2 = test_node_get_parent((IUnknown*)node); IHTMLDOMNode_Release(node); ok(node2 == NULL, "node != NULL\n"); } elem2 = test_elem_get_parent((IUnknown*)elem); ok(elem2 != NULL, "elem2 == NULL\n"); test_node_name((IUnknown*)elem2, "BODY"); elem3 = test_elem_get_parent((IUnknown*)elem2); IHTMLElement_Release(elem2); ok(elem3 != NULL, "elem3 == NULL\n"); test_node_name((IUnknown*)elem3, "HTML"); elem2 = test_elem_get_parent((IUnknown*)elem3); IHTMLElement_Release(elem3); ok(elem2 == NULL, "elem2 != NULL\n"); test_elem_getelembytag((IUnknown*)elem, ET_OPTION, 2); test_elem_getelembytag((IUnknown*)elem, ET_SELECT, 0); test_elem_getelembytag((IUnknown*)elem, ET_HTML, 0); test_elem_innertext(elem, "opt1opt2"); IHTMLElement_Release(elem); } elem = get_elem_by_id(doc, sW, TRUE); if(elem) { IHTMLSelectElement *select; hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLSelectElement, (void**)&select); ok(hres == S_OK, "Could not get IHTMLSelectElement interface: %08x\n", hres); test_select_elem(select); test_elem_title((IUnknown*)select, NULL); test_elem_set_title((IUnknown*)select, "Title"); test_elem_title((IUnknown*)select, "Title"); test_elem_offset((IUnknown*)select); node = get_first_child((IUnknown*)select); ok(node != NULL, "node == NULL\n"); if(node) { test_elem_type((IUnknown*)node, ET_OPTION); IHTMLDOMNode_Release(node); } type = get_node_type((IUnknown*)select); ok(type == 1, "type=%ld\n", type); IHTMLSelectElement_Release(select); hres = IHTMLElement_get_document(elem, &disp); ok(hres == S_OK, "get_document failed: %08x\n", hres); ok(iface_cmp((IUnknown*)disp, (IUnknown*)doc), "disp != doc\n"); IHTMLElement_Release(elem); } elem = get_elem_by_id(doc, scW, TRUE); if(elem) { IHTMLScriptElement *script; BSTR type; hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLScriptElement, (void**)&script); ok(hres == S_OK, "Could not get IHTMLScriptElement interface: %08x\n", hres); if(hres == S_OK) { VARIANT_BOOL vb; hres = IHTMLScriptElement_get_type(script, &type); ok(hres == S_OK, "get_type failed: %08x\n", hres); ok(!lstrcmpW(type, text_javascriptW), "Unexpected type %s\n", dbgstr_w(type)); SysFreeString(type); /* test defer */ hres = IHTMLScriptElement_put_defer(script, VARIANT_TRUE); ok(hres == S_OK, "get_type failed: %08x\n", hres); hres = IHTMLScriptElement_get_defer(script, &vb); ok(hres == S_OK, "get_type failed: %08x\n", hres); ok(vb == VARIANT_TRUE, "get_type failed: %08x\n", hres); hres = IHTMLScriptElement_put_defer(script, VARIANT_FALSE); ok(hres == S_OK, "get_type failed: %08x\n", hres); } IHTMLScriptElement_Release(script); } elem = get_elem_by_id(doc, inW, TRUE); if(elem) { IHTMLInputElement *input; hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLInputElement, (void**)&input); ok(hres == S_OK, "Could not get IHTMLInputElement: %08x\n", hres); test_elem_id((IUnknown*)elem, "in"); test_elem_put_id((IUnknown*)elem, "newin"); test_input_get_disabled(input, VARIANT_FALSE); test_input_set_disabled(input, VARIANT_TRUE); test_input_set_disabled(input, VARIANT_FALSE); test_elem3_set_disabled((IUnknown*)input, VARIANT_TRUE); test_input_get_disabled(input, VARIANT_TRUE); test_elem3_set_disabled((IUnknown*)input, VARIANT_FALSE); test_input_get_disabled(input, VARIANT_FALSE); test_elem_client_size((IUnknown*)elem); test_node_get_value_str((IUnknown*)elem, NULL); test_node_put_value_str((IUnknown*)elem, "test"); test_node_get_value_str((IUnknown*)elem, NULL); test_input_value((IUnknown*)elem, NULL); test_input_put_value((IUnknown*)elem, "test"); test_input_value((IUnknown*)elem, NULL); test_elem_class((IUnknown*)elem, "testclass"); test_elem_tabindex((IUnknown*)elem, 2); test_elem_set_tabindex((IUnknown*)elem, 3); test_elem_title((IUnknown*)elem, "test title"); test_input_get_defaultchecked(input, VARIANT_FALSE); test_input_set_defaultchecked(input, VARIANT_TRUE); test_input_set_defaultchecked(input, VARIANT_FALSE); test_input_get_checked(input, VARIANT_FALSE); test_input_set_checked(input, VARIANT_TRUE); test_input_set_checked(input, VARIANT_FALSE); IHTMLInputElement_Release(input); IHTMLElement_Release(elem); } elem = get_elem_by_id(doc, imgidW, TRUE); if(elem) { test_img_src((IUnknown*)elem, ""); test_img_set_src((IUnknown*)elem, "about:blank"); test_img_alt((IUnknown*)elem, NULL); test_img_set_alt((IUnknown*)elem, "alt test"); IHTMLElement_Release(elem); } elem = get_doc_elem_by_id(doc, tblW); ok(elem != NULL, "elem == NULL\n"); if(elem) { test_table_elem(elem); IHTMLElement_Release(elem); } elem = get_doc_elem_by_id(doc, row2W); ok(elem != NULL, "elem == NULL\n"); if(elem) { test_tr_elem(elem); IHTMLElement_Release(elem); } elem = get_doc_elem_by_id(doc, ifrW); ok(elem != NULL, "elem == NULL\n"); if(elem) { test_iframe_elem(elem); IHTMLElement_Release(elem); } hres = IHTMLDocument2_get_body(doc, &elem); ok(hres == S_OK, "get_body failed: %08x\n", hres); node = get_first_child((IUnknown*)elem); ok(node != NULL, "node == NULL\n"); if(node) { test_ifaces((IUnknown*)node, text_iids); test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode); node2 = get_first_child((IUnknown*)node); ok(!node2, "node2 != NULL\n"); type = get_node_type((IUnknown*)node); ok(type == 3, "type=%ld\n", type); test_node_get_value_str((IUnknown*)node, "text test"); test_node_put_value_str((IUnknown*)elem, "test text"); test_node_get_value_str((IUnknown*)node, "text test"); IHTMLDOMNode_Release(node); } child_col = get_child_nodes((IUnknown*)elem); ok(child_col != NULL, "child_coll == NULL\n"); if(child_col) { long length = 0; test_disp((IUnknown*)child_col, &DIID_DispDOMChildrenCollection); hres = IHTMLDOMChildrenCollection_get_length(child_col, &length); ok(hres == S_OK, "get_length failed: %08x\n", hres); ok(length, "length=0\n"); node = get_child_item(child_col, 0); ok(node != NULL, "node == NULL\n"); if(node) { type = get_node_type((IUnknown*)node); ok(type == 3, "type=%ld\n", type); IHTMLDOMNode_Release(node); } node = get_child_item(child_col, 1); ok(node != NULL, "node == NULL\n"); if(node) { type = get_node_type((IUnknown*)node); ok(type == 8, "type=%ld\n", type); test_elem_id((IUnknown*)node, NULL); IHTMLDOMNode_Release(node); } disp = (void*)0xdeadbeef; hres = IHTMLDOMChildrenCollection_item(child_col, 6000, &disp); ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); ok(disp == (void*)0xdeadbeef, "disp=%p\n", disp); disp = (void*)0xdeadbeef; hres = IHTMLDOMChildrenCollection_item(child_col, length, &disp); ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres); ok(disp == (void*)0xdeadbeef, "disp=%p\n", disp); test_child_col_disp(child_col); IHTMLDOMChildrenCollection_Release(child_col); } test_elem3_get_disabled((IUnknown*)elem, VARIANT_FALSE); test_elem3_set_disabled((IUnknown*)elem, VARIANT_TRUE); test_elem3_set_disabled((IUnknown*)elem, VARIANT_FALSE); IHTMLElement_Release(elem); test_stylesheets(doc); test_create_option_elem(doc); elem = get_doc_elem_by_id(doc, tblW); ok(elem != NULL, "elem = NULL\n"); test_elem_set_innertext(elem, "inner text"); IHTMLElement_Release(elem); test_doc_title(doc, "test"); test_doc_set_title(doc, "test title"); test_doc_title(doc, "test title"); disp = NULL; hres = IHTMLDocument2_get_Script(doc, &disp); ok(hres == S_OK, "get_Script failed: %08x\n", hres); if(hres == S_OK) { IDispatchEx *dispex; hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); ok(hres == S_OK, "IDispatch_QueryInterface failed: %08x\n", hres); if(hres == S_OK) { DISPID pid = -1; BSTR str = a2bstr("Testing"); hres = IDispatchEx_GetDispID(dispex, str, 1, &pid); todo_wine ok(hres == S_OK, "GetDispID failed: %08x\n", hres); todo_wine ok(pid != -1, "pid == -1\n"); SysFreeString(str); IDispatchEx_Release(dispex); } } IDispatch_Release(disp); hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3); ok(hres == S_OK, "Could not get IHTMLDocument3 iface: %08x\n", hres); str = a2bstr("img"); hres = IHTMLDocument3_getElementsByTagName(doc3, str, &col); SysFreeString(str); ok(hres == S_OK, "getElementByTag(%s) failed: %08x\n", dbgstr_w(ifrW), hres); if(hres == S_OK) { static const elem_type_t img_types[] = { ET_IMG }; test_elem_collection((IUnknown*)col, img_types, sizeof(img_types)/sizeof(img_types[0])); IHTMLElementCollection_Release(col); } IHTMLDocument3_Release(doc3); } static void test_create_elems(IHTMLDocument2 *doc) { IHTMLElement *elem, *body, *elem2; IHTMLDOMNode *node, *node2, *node3, *comment; IHTMLDocument5 *doc5; IDispatch *disp; VARIANT var; long type; HRESULT hres; BSTR str; static const elem_type_t types1[] = { ET_TESTG }; elem = test_create_elem(doc, "TEST"); test_elem_tag((IUnknown*)elem, "TEST"); type = get_node_type((IUnknown*)elem); ok(type == 1, "type=%ld\n", type); test_ifaces((IUnknown*)elem, elem_iids); test_disp((IUnknown*)elem, &DIID_DispHTMLGenericElement); hres = IHTMLDocument2_get_body(doc, &body); ok(hres == S_OK, "get_body failed: %08x\n", hres); test_node_has_child((IUnknown*)body, VARIANT_FALSE); node = test_node_append_child((IUnknown*)body, (IUnknown*)elem); test_node_has_child((IUnknown*)body, VARIANT_TRUE); elem2 = get_elem_iface((IUnknown*)node); IHTMLElement_Release(elem2); hres = IHTMLElement_get_all(body, &disp); ok(hres == S_OK, "get_all failed: %08x\n", hres); test_elem_collection((IUnknown*)disp, types1, sizeof(types1)/sizeof(types1[0])); IDispatch_Release(disp); test_node_remove_child((IUnknown*)body, node); hres = IHTMLElement_get_all(body, &disp); ok(hres == S_OK, "get_all failed: %08x\n", hres); test_elem_collection((IUnknown*)disp, NULL, 0); IDispatch_Release(disp); test_node_has_child((IUnknown*)body, VARIANT_FALSE); IHTMLElement_Release(elem); IHTMLDOMNode_Release(node); node = test_create_text(doc, "test"); test_ifaces((IUnknown*)node, text_iids); test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode); V_VT(&var) = VT_NULL; node2 = test_node_insertbefore((IUnknown*)body, node, &var); IHTMLDOMNode_Release(node); node = test_create_text(doc, "insert "); V_VT(&var) = VT_DISPATCH; V_DISPATCH(&var) = (IDispatch*)node2; node3 = test_node_insertbefore((IUnknown*)body, node, &var); IHTMLDOMNode_Release(node); IHTMLDOMNode_Release(node2); IHTMLDOMNode_Release(node3); test_elem_innertext(body, "insert test"); hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument5, (void**)&doc5); if(hres == S_OK) { str = a2bstr("testing"); hres = IHTMLDocument5_createComment(doc5, str, &comment); SysFreeString(str); ok(hres == S_OK, "createComment failed: %08x\n", hres); if(hres == S_OK) { type = get_node_type((IUnknown*)comment); ok(type == 8, "type=%ld, expected 8\n", type); test_node_get_value_str((IUnknown*)comment, "testing"); IHTMLDOMNode_Release(comment); } IHTMLDocument5_Release(doc5); } IHTMLElement_Release(body); } static void test_exec(IUnknown *unk, const GUID *grpid, DWORD cmdid, VARIANT *in, VARIANT *out) { IOleCommandTarget *cmdtrg; HRESULT hres; hres = IHTMLTxtRange_QueryInterface(unk, &IID_IOleCommandTarget, (void**)&cmdtrg); ok(hres == S_OK, "Could not get IOleCommandTarget interface: %08x\n", hres); hres = IOleCommandTarget_Exec(cmdtrg, grpid, cmdid, 0, in, out); ok(hres == S_OK, "Exec failed: %08x\n", hres); IOleCommandTarget_Release(cmdtrg); } static void test_indent(IHTMLDocument2 *doc) { IHTMLElementCollection *col; IHTMLTxtRange *range; HRESULT hres; static const elem_type_t all_types[] = { ET_HTML, ET_HEAD, ET_TITLE, ET_BODY, ET_BR, ET_A, }; static const elem_type_t indent_types[] = { ET_HTML, ET_HEAD, ET_TITLE, ET_BODY, ET_BLOCKQUOTE, ET_P, ET_BR, ET_A, }; hres = IHTMLDocument2_get_all(doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); IHTMLElementCollection_Release(col); range = test_create_body_range(doc); test_exec((IUnknown*)range, &CGID_MSHTML, IDM_INDENT, NULL, NULL); IHTMLTxtRange_Release(range); hres = IHTMLDocument2_get_all(doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); test_elem_collection((IUnknown*)col, indent_types, sizeof(indent_types)/sizeof(indent_types[0])); IHTMLElementCollection_Release(col); } static void test_cond_comment(IHTMLDocument2 *doc) { IHTMLElementCollection *col; HRESULT hres; static const elem_type_t all_types[] = { ET_HTML, ET_HEAD, ET_TITLE, ET_BODY, ET_BR }; hres = IHTMLDocument2_get_all(doc, &col); ok(hres == S_OK, "get_all failed: %08x\n", hres); test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0])); IHTMLElementCollection_Release(col); } 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; static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0}; hres = IHTMLDocument2_get_readyState(notif_doc, &state); ok(hres == S_OK, "get_readyState failed: %08x\n", hres); if(!lstrcmpW(state, completeW)) 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 IHTMLDocument2 *create_doc_with_string(const char *str) { IPersistStreamInit *init; IStream *stream; IHTMLDocument2 *doc; HGLOBAL mem; SIZE_T len; notif_doc = doc = create_document(); if(!doc) return NULL; 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); return doc; } 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); } typedef void (*domtest_t)(IHTMLDocument2*); static void run_domtest(const char *str, domtest_t test) { IHTMLDocument2 *doc; IHTMLElement *body = NULL; ULONG ref; MSG msg; HRESULT hres; doc = create_doc_with_string(str); if(!doc) return; 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); test(doc); }else { skip("Could not get document body. Assuming no Gecko installed.\n"); } ref = IHTMLDocument2_Release(doc); ok(!ref || ref == 1, /* Vista */ "ref = %d\n", ref); } static void gecko_installer_workaround(BOOL disable) { HKEY hkey; DWORD res; static BOOL has_url = FALSE; static char url[2048]; if(!disable && !has_url) return; res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey); if(res != ERROR_SUCCESS) return; if(disable) { DWORD type, size = sizeof(url); res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size); if(res == ERROR_SUCCESS && type == REG_SZ) has_url = TRUE; RegDeleteValue(hkey, "GeckoUrl"); }else { RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1); } RegCloseKey(hkey); } /* Check if Internet Explorer is configured to run in "Enhanced Security Configuration" (aka hardened mode) */ /* Note: this code is duplicated in dlls/mshtml/tests/dom.c, dlls/mshtml/tests/script.c and dlls/urlmon/tests/misc.c */ static BOOL is_ie_hardened(void) { HKEY zone_map; DWORD ie_harden, type, size; ie_harden = 0; if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ZoneMap", 0, KEY_QUERY_VALUE, &zone_map) == ERROR_SUCCESS) { size = sizeof(DWORD); if (RegQueryValueEx(zone_map, "IEHarden", NULL, &type, (LPBYTE) &ie_harden, &size) != ERROR_SUCCESS || type != REG_DWORD) { ie_harden = 0; } RegCloseKey(zone_map); } return ie_harden != 0; } START_TEST(dom) { gecko_installer_workaround(TRUE); CoInitialize(NULL); run_domtest(doc_str1, test_doc_elem); run_domtest(range_test_str, test_txtrange); run_domtest(range_test2_str, test_txtrange2); if (winetest_interactive || ! is_ie_hardened()) { run_domtest(elem_test_str, test_elems); }else { skip("IE running in Enhanced Security Configuration\n"); } run_domtest(doc_blank, test_create_elems); run_domtest(doc_blank, test_defaults); run_domtest(indent_test_str, test_indent); run_domtest(cond_comment_str, test_cond_comment); CoUninitialize(); gecko_installer_workaround(FALSE); }