From 43eb75a9e4f8db8294529787fcbed6985cff35a0 Mon Sep 17 00:00:00 2001 From: Christoph von Wittich Date: Wed, 4 Feb 2009 14:36:08 +0000 Subject: [PATCH] sync mshtml and shdocvw winetests with wine 1.1.14 svn path=/trunk/; revision=39390 --- rostests/winetests/directory.rbuild | 3 + rostests/winetests/mshtml/dom.c | 1789 ++++++++++++++++- rostests/winetests/mshtml/htmldoc.c | 153 +- rostests/winetests/mshtml/misc.c | 3 +- rostests/winetests/mshtml/protocol.c | 14 +- rostests/winetests/mshtml/script.c | 236 ++- rostests/winetests/shdocvw/intshcut.c | 224 +++ rostests/winetests/shdocvw/shdocvw.c | 360 ++++ rostests/winetests/shdocvw/shdocvw.rbuild | 23 + rostests/winetests/shdocvw/shortcut.c | 231 +++ rostests/winetests/shdocvw/testlist.c | 22 + rostests/winetests/shdocvw/webbrowser.c | 2137 +++++++++++++++++++++ 12 files changed, 5053 insertions(+), 142 deletions(-) create mode 100644 rostests/winetests/shdocvw/intshcut.c create mode 100644 rostests/winetests/shdocvw/shdocvw.c create mode 100644 rostests/winetests/shdocvw/shdocvw.rbuild create mode 100644 rostests/winetests/shdocvw/shortcut.c create mode 100644 rostests/winetests/shdocvw/testlist.c create mode 100644 rostests/winetests/shdocvw/webbrowser.c diff --git a/rostests/winetests/directory.rbuild b/rostests/winetests/directory.rbuild index a8c522d41e6..dee46358508 100644 --- a/rostests/winetests/directory.rbuild +++ b/rostests/winetests/directory.rbuild @@ -118,6 +118,9 @@ + + + diff --git a/rostests/winetests/mshtml/dom.c b/rostests/winetests/mshtml/dom.c index 4540ed405b8..36946808f89 100644 --- a/rostests/winetests/mshtml/dom.c +++ b/rostests/winetests/mshtml/dom.c @@ -1,5 +1,5 @@ /* - * Copyright 2007 Jacek Caban for CodeWeavers + * 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 @@ -40,18 +40,23 @@ static const char range_test2_str[] = "abc
123

def"; static const char elem_test_str[] = "test" - "text 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}; @@ -84,29 +89,34 @@ typedef enum { ET_TEST, ET_TESTG, ET_COMMENT, - ET_IMG + ET_IMG, + ET_TR, + ET_TD, + ET_IFRAME } elem_type_t; -static REFIID const none_iids[] = { +static const IID * const none_iids[] = { &IID_IUnknown, NULL }; -static REFIID const elem_iids[] = { +static const IID * const elem_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const body_iids[] = { +static const IID * const body_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLTextContainer, &IID_IHTMLBodyElement, &IID_IDispatchEx, @@ -114,22 +124,24 @@ static REFIID const body_iids[] = { NULL }; -static REFIID const anchor_iids[] = { +static const IID * const anchor_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLAnchorElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const input_iids[] = { +static const IID * const input_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLInputElement, &IID_IHTMLInputTextElement, &IID_IDispatchEx, @@ -137,75 +149,80 @@ static REFIID const input_iids[] = { NULL }; -static REFIID const select_iids[] = { +static const IID * const select_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLSelectElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const textarea_iids[] = { +static const IID * const textarea_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLTextAreaElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const option_iids[] = { +static const IID * const option_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLOptionElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const table_iids[] = { +static const IID * const table_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLTable, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const script_iids[] = { +static const IID * const script_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLScriptElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const text_iids[] = { +static const IID * const text_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLDOMTextNode, NULL }; -static REFIID const location_iids[] = { +static const IID * const location_iids[] = { &IID_IDispatch, &IID_IHTMLLocation, NULL }; -static REFIID const window_iids[] = { +static const IID * const window_iids[] = { &IID_IDispatch, &IID_IHTMLWindow2, &IID_IHTMLWindow3, @@ -213,39 +230,94 @@ static REFIID const window_iids[] = { NULL }; -static REFIID const comment_iids[] = { +static const IID * const comment_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IHTMLCommentElement, &IID_IDispatchEx, &IID_IConnectionPointContainer, NULL }; -static REFIID const img_iids[] = { +static const IID * const img_iids[] = { &IID_IHTMLDOMNode, &IID_IHTMLDOMNode2, &IID_IHTMLElement, &IID_IHTMLElement2, + &IID_IHTMLElement3, &IID_IDispatchEx, &IID_IHTMLImgElement, &IID_IConnectionPointContainer, NULL }; -static REFIID const generic_iids[] = { +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, + NULL +}; + +static const IID * const cstyle_iids[] = { + &IID_IUnknown, + &IID_IDispatch, + &IID_IDispatchEx, + &IID_IHTMLCurrentStyle, + NULL +}; + typedef struct { const char *tag; REFIID *iids; @@ -257,7 +329,7 @@ static const elem_type_info_t elem_type_infos[] = { {"HTML", elem_iids, NULL}, {"HEAD", elem_iids, NULL}, {"TITLE", elem_iids, NULL}, - {"BODY", body_iids, NULL}, + {"BODY", body_iids, &DIID_DispHTMLBody}, {"A", anchor_iids, NULL}, {"INPUT", input_iids, &DIID_DispHTMLInputElement}, {"SELECT", select_iids, &DIID_DispHTMLSelectElement}, @@ -267,13 +339,16 @@ static const elem_type_info_t elem_type_infos[] = { {"BLOCKQUOTE",elem_iids, NULL}, {"P", elem_iids, NULL}, {"BR", elem_iids, NULL}, - {"TABLE", table_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} + {"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) @@ -316,15 +391,39 @@ static BSTR a2bstr(const char *str) 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; } @@ -400,6 +499,17 @@ static IHTMLElement2 *_get_elem2_iface(unsigned line, IUnknown *unk) 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) { @@ -462,6 +572,58 @@ static void _test_elem_type(unsigned line, IUnknown *unk, elem_type_t type) _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) { @@ -496,6 +658,12 @@ static void _test_elem_offset(unsigned line, IUnknown *unk) 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); } @@ -841,7 +1009,7 @@ static void _test_elem_collection(unsigned line, IUnknown *unk, HRESULT hres; hres = IUnknown_QueryInterface(unk, &IID_IHTMLElementCollection, (void**)&col); - ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); + ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres); test_disp((IUnknown*)col, &DIID_DispHTMLElementCollection); @@ -883,6 +1051,85 @@ static void _test_elem_collection(unsigned line, IUnknown *unk, IHTMLElementCollection_Release(col); } +#define test_elem_getelembytag(u,t,l) _test_elem_getelembytag(__LINE__,u,t,l) +static void _test_elem_getelembytag(unsigned line, IUnknown *unk, elem_type_t type, long exlen) +{ + IHTMLElement2 *elem = _get_elem2_iface(line, unk); + IHTMLElementCollection *col = NULL; + elem_type_t *types = NULL; + BSTR tmp; + int i; + HRESULT hres; + + tmp = a2bstr(elem_type_infos[type].tag); + hres = IHTMLElement2_getElementsByTagName(elem, tmp, &col); + SysFreeString(tmp); + IHTMLElement2_Release(elem); + ok_(__FILE__,line) (hres == S_OK, "getElementByTagName failed: %08x\n", hres); + ok_(__FILE__,line) (col != NULL, "col == NULL\n"); + + if(exlen) { + types = HeapAlloc(GetProcessHeap(), 0, exlen*sizeof(elem_type_t)); + 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) @@ -2056,11 +3412,14 @@ static void test_elems(IHTMLDocument2 *doc) { IHTMLElementCollection *col; IHTMLDOMChildrenCollection *child_col; - IHTMLElement *elem; + 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}; @@ -2068,6 +3427,9 @@ static void test_elems(IHTMLDocument2 *doc) 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, @@ -2084,9 +3446,14 @@ static void test_elems(IHTMLDocument2 *doc) ET_TEXTAREA, ET_TABLE, ET_TBODY, + ET_TR, + ET_TR, + ET_TD, + ET_TD, ET_SCRIPT, ET_TEST, - ET_IMG + ET_IMG, + ET_IFRAME }; static const elem_type_t item_types[] = { @@ -2101,6 +3468,36 @@ static void test_elems(IHTMLDocument2 *doc) 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); @@ -2139,12 +3536,32 @@ static void test_elems(IHTMLDocument2 *doc) node = test_node_get_parent((IUnknown*)node2); IHTMLDOMNode_Release(node2); ok(node != NULL, "node == NULL\n"); - 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"); + 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); } @@ -2174,6 +3591,11 @@ static void test_elems(IHTMLDocument2 *doc) 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); } @@ -2185,10 +3607,26 @@ static void test_elems(IHTMLDocument2 *doc) hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLScriptElement, (void**)&script); ok(hres == S_OK, "Could not get IHTMLScriptElement interface: %08x\n", hres); - 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); + 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); } @@ -2205,6 +3643,10 @@ static void test_elems(IHTMLDocument2 *doc) 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); @@ -2218,18 +3660,48 @@ static void test_elems(IHTMLDocument2 *doc) 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); @@ -2296,19 +3768,73 @@ static void test_elems(IHTMLDocument2 *doc) 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; + 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 }; @@ -2341,14 +3867,49 @@ static void test_create_elems(IHTMLDocument2 *doc) IDispatch_Release(disp); test_node_has_child((IUnknown*)body, VARIANT_FALSE); - IHTMLElement_Release(body); 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) @@ -2406,6 +3967,25 @@ static void test_indent(IHTMLDocument2 *doc) 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; @@ -2524,6 +4104,9 @@ static void run_domtest(const char *str, domtest_t test) 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)) { @@ -2542,7 +4125,9 @@ static void run_domtest(const char *str, domtest_t test) } ref = IHTMLDocument2_Release(doc); - ok(!ref, "ref = %d\n", ref); + ok(!ref || + ref == 1, /* Vista */ + "ref = %d\n", ref); } static void gecko_installer_workaround(BOOL disable) @@ -2575,6 +4160,27 @@ static void gecko_installer_workaround(BOOL disable) 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); @@ -2583,10 +4189,15 @@ START_TEST(dom) run_domtest(doc_str1, test_doc_elem); run_domtest(range_test_str, test_txtrange); run_domtest(range_test2_str, test_txtrange2); - run_domtest(elem_test_str, test_elems); + 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); diff --git a/rostests/winetests/mshtml/htmldoc.c b/rostests/winetests/mshtml/htmldoc.c index 4de528676cd..e4ae1449875 100644 --- a/rostests/winetests/mshtml/htmldoc.c +++ b/rostests/winetests/mshtml/htmldoc.c @@ -25,6 +25,7 @@ #include "windef.h" #include "winbase.h" +#include "initguid.h" #include "ole2.h" #include "mshtml.h" #include "docobj.h" @@ -36,7 +37,8 @@ #include "idispids.h" #include "shlguid.h" -#include "initguid.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +DEFINE_GUID(IID_IProxyManager,0x00000008,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); DEFINE_OLEGUID(CGID_DocHostCmdPriv, 0x000214D4L, 0, 0); #define DEFINE_EXPECT(func) \ @@ -136,6 +138,10 @@ DEFINE_EXPECT(RequestUIActivate); DEFINE_EXPECT(InPlaceFrame_SetBorderSpace); DEFINE_EXPECT(InPlaceUIWindow_SetActiveObject); DEFINE_EXPECT(GetExternal); +DEFINE_EXPECT(EnableModeless_TRUE); +DEFINE_EXPECT(EnableModeless_FALSE); +DEFINE_EXPECT(Frame_EnableModeless_TRUE); +DEFINE_EXPECT(Frame_EnableModeless_FALSE); static IUnknown *doc_unk; static BOOL expect_LockContainer_fLock; @@ -143,7 +149,7 @@ static BOOL expect_InPlaceUIWindow_SetActiveObject_active = TRUE; static BOOL ipsex; static BOOL set_clientsite = FALSE, container_locked = FALSE; static BOOL readystate_set_loading = FALSE, load_from_stream; -static BOOL editmode = FALSE; +static BOOL editmode = FALSE, show_failed; static int stream_read, protocol_read; static enum load_state_t { LD_DOLOAD, @@ -649,11 +655,13 @@ static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, D readystate_set_loading = FALSE; load_state = LD_LOADING; } - test_readyState(NULL); + if(!editmode || load_state != LD_LOADING || !called_Exec_Explorer_69) + test_readyState(NULL); return S_OK; case 1005: CHECK_EXPECT(OnChanged_1005); - test_readyState(NULL); + if(!editmode) + test_readyState(NULL); load_state = LD_INTERACTIVE; return S_OK; } @@ -1007,8 +1015,10 @@ static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMon BINDSTATUS_ENDDOWNLOADDATA, NULL); ok(hres == S_OK, "OnProgress(BINDSTATUS_ENDDOWNLOADDATA) failed: %08x\n", hres); + SET_EXPECT(GetBindResult); hres = IBindStatusCallback_OnStopBinding(callback, S_OK, NULL); ok(hres == S_OK, "OnStopBinding failed: %08x\n", hres); + SET_CALLED(GetBindResult); /* IE7 */ IBindStatusCallback_Release(callback); @@ -1304,7 +1314,10 @@ static HRESULT WINAPI InPlaceFrame_SetStatusText(IOleInPlaceFrame *iface, LPCOLE static HRESULT WINAPI InPlaceFrame_EnableModeless(IOleInPlaceFrame *iface, BOOL fEnable) { - ok(0, "unexpected call\n"); + if(fEnable) + CHECK_EXPECT(Frame_EnableModeless_TRUE); + else + CHECK_EXPECT(Frame_EnableModeless_FALSE); return E_NOTIMPL; } @@ -1664,11 +1677,6 @@ static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocum expect_status_text = NULL; hres = IOleDocumentView_UIActivate(view, TRUE); - - if(FAILED(hres)) { - skip("UIActivate failed: %08x\n", hres); - return hres; - } ok(hres == S_OK, "UIActivate failed: %08x\n", hres); CHECK_CALLED(CanInPlaceActivate); @@ -1724,6 +1732,14 @@ static HRESULT WINAPI DocumentSite_ActivateMe(IOleDocumentSite *iface, IOleDocum expect_status_text = (load_state == LD_COMPLETE ? (LPCOLESTR)0xdeadbeef : NULL); hres = IOleDocumentView_Show(view, TRUE); + if(FAILED(hres)) { + win_skip("Show failed\n"); + if(activeobj) + IOleInPlaceActiveObject_Release(activeobj); + IOleDocument_Release(document); + show_failed = TRUE; + return S_OK; + } ok(hres == S_OK, "Show failed: %08x\n", hres); CHECK_CALLED(CanInPlaceActivate); @@ -1918,7 +1934,10 @@ static HRESULT WINAPI DocHostUIHandler_UpdateUI(IDocHostUIHandler2 *iface) static HRESULT WINAPI DocHostUIHandler_EnableModeless(IDocHostUIHandler2 *iface, BOOL fEnable) { - ok(0, "unexpected call\n"); + if(fEnable) + CHECK_EXPECT(EnableModeless_TRUE); + else + CHECK_EXPECT(EnableModeless_FALSE); return E_NOTIMPL; } @@ -2635,6 +2654,7 @@ static void test_Load(IPersistMoniker *persist) } SET_EXPECT(OnChanged_READYSTATE); SET_EXPECT(Exec_ShellDocView_84); + SET_EXPECT(IsSystemMoniker); SET_EXPECT(BindToStorage); SET_EXPECT(SetActiveObject); if(set_clientsite) { @@ -2672,6 +2692,7 @@ static void test_Load(IPersistMoniker *persist) container_locked = TRUE; } CHECK_CALLED(OnChanged_READYSTATE); + SET_CALLED(IsSystemMoniker); /* IE7 */ SET_CALLED(Exec_ShellDocView_84); CHECK_CALLED(BindToStorage); SET_CALLED(SetActiveObject); /* FIXME */ @@ -2719,6 +2740,10 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) SET_EXPECT(UnlockRequest); } SET_EXPECT(Exec_Explorer_69); + SET_EXPECT(EnableModeless_TRUE); /* IE7 */ + SET_EXPECT(Frame_EnableModeless_TRUE); /* IE7 */ + SET_EXPECT(EnableModeless_FALSE); /* IE7 */ + SET_EXPECT(Frame_EnableModeless_FALSE); /* IE7 */ SET_EXPECT(OnChanged_1005); SET_EXPECT(OnChanged_READYSTATE); SET_EXPECT(Exec_SETPROGRESSPOS); @@ -2726,6 +2751,7 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) SET_EXPECT(Exec_ShellDocView_103); SET_EXPECT(Exec_MSHTML_PARSECOMPLETE); SET_EXPECT(Exec_HTTPEQUIV_DONE); + SET_EXPECT(SetStatusText); expect_status_text = (LPWSTR)0xdeadbeef; /* TODO */ while(!called_Exec_HTTPEQUIV_DONE && GetMessage(&msg, NULL, 0, 0)) { @@ -2766,6 +2792,10 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) } } SET_CALLED(Exec_Explorer_69); + SET_CALLED(EnableModeless_TRUE); /* IE7 */ + SET_CALLED(Frame_EnableModeless_TRUE); /* IE7 */ + SET_CALLED(EnableModeless_FALSE); /* IE7 */ + SET_CALLED(Frame_EnableModeless_FALSE); /* IE7 */ CHECK_CALLED(OnChanged_1005); CHECK_CALLED(OnChanged_READYSTATE); CHECK_CALLED(Exec_SETPROGRESSPOS); @@ -2773,6 +2803,7 @@ static void test_download(BOOL verb_done, BOOL css_dwl, BOOL css_try_dwl) SET_CALLED(Exec_ShellDocView_103); CHECK_CALLED(Exec_MSHTML_PARSECOMPLETE); CHECK_CALLED(Exec_HTTPEQUIV_DONE); + SET_CALLED(SetStatusText); load_state = LD_COMPLETE; @@ -3044,6 +3075,7 @@ static void test_exec_editmode(IUnknown *unk, BOOL loaded) SET_EXPECT(Invoke_AMBIENT_SILENT); SET_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); SET_EXPECT(OnChanged_READYSTATE); + SET_EXPECT(IsSystemMoniker); SET_EXPECT(Exec_ShellDocView_84); if(loaded) SET_EXPECT(BindToStorage); @@ -3069,6 +3101,7 @@ static void test_exec_editmode(IUnknown *unk, BOOL loaded) CHECK_CALLED(Invoke_AMBIENT_SILENT); CHECK_CALLED(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); CHECK_CALLED(OnChanged_READYSTATE); + SET_CALLED(IsSystemMoniker); /* IE7 */ SET_CALLED(Exec_ShellDocView_84); if(loaded) CHECK_CALLED(BindToStorage); @@ -3199,7 +3232,7 @@ static HWND create_container_window(void) 515, 530, NULL, NULL, NULL, NULL); } -static HRESULT test_DoVerb(IOleObject *oleobj) +static void test_DoVerb(IOleObject *oleobj) { RECT rect = {0,0,500,500}; HRESULT hres; @@ -3212,8 +3245,6 @@ static HRESULT test_DoVerb(IOleObject *oleobj) expect_LockContainer_fLock = TRUE; hres = IOleObject_DoVerb(oleobj, OLEIVERB_SHOW, NULL, &ClientSite, -1, container_hwnd, &rect); - if(FAILED(hres)) - return hres; ok(hres == S_OK, "DoVerb failed: %08x\n", hres); if(!container_locked) { @@ -3222,8 +3253,6 @@ static HRESULT test_DoVerb(IOleObject *oleobj) container_locked = TRUE; } CHECK_CALLED(ActivateMe); - - return hres; } #define CLIENTSITE_EXPECTPATH 0x00000001 @@ -3465,7 +3494,7 @@ static void test_InPlaceDeactivate(IUnknown *unk, BOOL expect_call) IOleInPlaceObjectWindowless_Release(windowlessobj); } -static HRESULT test_Activate(IUnknown *unk, DWORD flags) +static void test_Activate(IUnknown *unk, DWORD flags) { IOleObject *oleobj = NULL; IOleDocumentView *docview; @@ -3480,8 +3509,6 @@ static HRESULT test_Activate(IUnknown *unk, DWORD flags) hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj); ok(hres == S_OK, "QueryInterface(IID_IOleObject) failed: %08x\n", hres); - if(FAILED(hres)) - return hres; hres = IOleObject_GetUserClassID(oleobj, NULL); ok(hres == E_INVALIDARG, "GetUserClassID returned: %08x, expected E_INVALIDARG\n", hres); @@ -3494,8 +3521,7 @@ static HRESULT test_Activate(IUnknown *unk, DWORD flags) test_ClientSite(oleobj, flags); test_InPlaceDeactivate(unk, FALSE); - - hres = test_DoVerb(oleobj); + test_DoVerb(oleobj); if(call_UIActivate == CallUIActivate_AfterShow) { hres = IOleObject_QueryInterface(oleobj, &IID_IOleDocumentView, (void **)&docview); @@ -3523,8 +3549,6 @@ static HRESULT test_Activate(IUnknown *unk, DWORD flags) IOleObject_Release(oleobj); test_OnFrameWindowActivate(unk); - - return hres; } static void test_Window(IUnknown *unk, BOOL expect_success) @@ -3612,9 +3636,23 @@ static void test_Hide(void) static HRESULT create_document(IUnknown **unk) { - HRESULT hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + IHTMLDocument5 *doc5; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void**)unk); ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres); + if(FAILED(hres)) + return hres; + + hres = IUnknown_QueryInterface(*unk, &IID_IHTMLDocument5, (void**)&doc5); + if(SUCCEEDED(hres)) { + IHTMLDocument5_Release(doc5); + }else { + win_skip("Could not get IHTMLDocument5, probably too old IE\n"); + IUnknown_Release(*unk); + } + return hres; } @@ -3707,27 +3745,32 @@ static void test_QueryInterface(IUnknown *unk) qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qirunnable=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qirunnable=%p, expected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode2, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_IPersistPropertyBag, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); qi = (void*)0xdeadbeef; hres = IUnknown_QueryInterface(unk, &IID_UndocumentedScriptIface, (void**)&qi); ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); - ok(qi == NULL, "qi=%p, ezpected NULL\n", qi); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); + + qi = (void*)0xdeadbeef; + hres = IUnknown_QueryInterface(unk, &IID_IMarshal, (void**)&qi); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(qi == NULL, "qi=%p, expected NULL\n", qi); } static void init_test(enum load_state_t ls) { @@ -3768,11 +3811,7 @@ static void test_HTMLDocument(BOOL do_load) if(!do_load) test_OnAmbientPropertyChange2(unk); - hres = test_Activate(unk, CLIENTSITE_EXPECTPATH); - if(FAILED(hres)) { - IUnknown_Release(unk); - return; - } + test_Activate(unk, CLIENTSITE_EXPECTPATH); if(do_load) { test_download(FALSE, TRUE, TRUE); @@ -3865,6 +3904,10 @@ static void test_HTMLDocument_hlink(void) test_GetCurMoniker(unk, NULL, NULL); test_Persist(unk); test_Navigate(unk); + if(show_failed) { + IUnknown_Release(unk); + return; + } test_download(FALSE, TRUE, TRUE); @@ -3999,7 +4042,11 @@ static void test_editing_mode(BOOL do_load) test_MSHTML_QueryStatus(unk, OLECMDF_SUPPORTED); test_download(TRUE, do_load, do_load); + + SET_EXPECT(SetStatusText); /* ignore race in native mshtml */ test_timer(EXPECT_UPDATEUI); + SET_CALLED(SetStatusText); + test_MSHTML_QueryStatus(unk, OLECMDF_SUPPORTED|OLECMDF_ENABLED); if(!do_load) { @@ -4088,6 +4135,31 @@ static void gecko_installer_workaround(BOOL disable) RegCloseKey(hkey); } +static void test_HTMLDoc_ISupportErrorInfo(void) +{ + HRESULT hres; + IUnknown *unk; + ISupportErrorInfo *sinfo; + LONG ref; + + hres = create_document(&unk); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_ISupportErrorInfo, (void**)&sinfo); + ok(hres == S_OK, "got %x\n", hres); + ok(sinfo != NULL, "got %p\n", sinfo); + if(sinfo) + { + hres = ISupportErrorInfo_InterfaceSupportsErrorInfo(sinfo, &IID_IErrorInfo); + ok(hres == S_FALSE, "Expected S_OK, got %x\n", hres); + IUnknown_Release(sinfo); + } + + ref = IUnknown_Release(unk); + ok(ref == 0, "ref=%d, expected 0\n", ref); +} + START_TEST(htmldoc) { gecko_installer_workaround(TRUE); @@ -4096,12 +4168,15 @@ START_TEST(htmldoc) container_hwnd = create_container_window(); register_protocol(); - test_HTMLDocument(FALSE); - test_HTMLDocument(TRUE); test_HTMLDocument_hlink(); - test_HTMLDocument_StreamLoad(); - test_editing_mode(FALSE); - test_editing_mode(TRUE); + if(!show_failed) { + test_HTMLDocument(FALSE); + test_HTMLDocument(TRUE); + test_HTMLDocument_StreamLoad(); + test_editing_mode(FALSE); + test_editing_mode(TRUE); + } + test_HTMLDoc_ISupportErrorInfo(); DestroyWindow(container_hwnd); CoUninitialize(); diff --git a/rostests/winetests/mshtml/misc.c b/rostests/winetests/mshtml/misc.c index 62c7e37901d..ed8de36b9a3 100644 --- a/rostests/winetests/mshtml/misc.c +++ b/rostests/winetests/mshtml/misc.c @@ -24,9 +24,8 @@ #include "windef.h" #include "winbase.h" #include "ole2.h" -#include "optary.h" - #include "initguid.h" +#include "optary.h" static void test_HTMLLoadOptions(void) { diff --git a/rostests/winetests/mshtml/protocol.c b/rostests/winetests/mshtml/protocol.c index 4e8b3d0c79a..36355bf36b0 100644 --- a/rostests/winetests/mshtml/protocol.c +++ b/rostests/winetests/mshtml/protocol.c @@ -266,9 +266,13 @@ static void res_sec_url_cmp(LPCWSTR url, DWORD size, LPCWSTR file) return; } + SetLastError(0xdeadbeef); len = SearchPathW(NULL, file, NULL, sizeof(buf)/sizeof(WCHAR), buf, NULL); if(!len) { - ok(0, "SearchPath failed: %u\n", GetLastError()); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + win_skip("SearchPathW is not implemented\n"); + else + ok(0, "SearchPath failed: %u\n", GetLastError()); return; } @@ -301,7 +305,7 @@ static void test_res_protocol(void) hres = CoGetClassObject(&CLSID_ResProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres); - if(!SUCCEEDED(hres)) + if(FAILED(hres)) return; hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); @@ -364,7 +368,7 @@ static void test_res_protocol(void) sizeof(buf)/sizeof(buf[0]), &size, 0); ok(hres == E_FAIL, "ParseUrl failed: %08x\n", hres); ok(buf[0] == '?', "buf changed\n"); - ok(size == 1, "size=%u, ezpected 1\n", size); + ok(size == 1, "size=%u, expected 1\n", size); buf[0] = '?'; hres = IInternetProtocolInfo_ParseUrl(protocol_info, blank_url, PARSE_DOMAIN, 0, buf, @@ -610,7 +614,7 @@ static void test_about_protocol(void) hres = CoGetClassObject(&CLSID_AboutProtocol, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)&unk); ok(hres == S_OK, "CoGetClassObject failed: %08x\n", hres); - if(!SUCCEEDED(hres)) + if(FAILED(hres)) return; hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&protocol_info); @@ -660,7 +664,7 @@ static void test_about_protocol(void) sizeof(buf)/sizeof(buf[0]), &size, 0); ok(hres == E_FAIL, "ParseUrl failed: %08x\n", hres); ok(buf[0] == '?', "buf changed\n"); - ok(size == 1, "size=%u, ezpected 1\n", size); + ok(size == 1, "size=%u, expected 1\n", size); buf[0] = '?'; hres = IInternetProtocolInfo_ParseUrl(protocol_info, about_blank_url, PARSE_DOMAIN, 0, buf, diff --git a/rostests/winetests/mshtml/script.c b/rostests/winetests/mshtml/script.c index bbd9c3cca5f..6178cdf3fc9 100644 --- a/rostests/winetests/mshtml/script.c +++ b/rostests/winetests/mshtml/script.c @@ -28,11 +28,14 @@ #include "ole2.h" #include "dispex.h" #include "mshtml.h" +#include "initguid.h" #include "activscp.h" #include "activdbg.h" #include "objsafe.h" #include "mshtmdid.h" +DEFINE_GUID(CLSID_IdentityUnmarshal,0x0000001b,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -81,6 +84,7 @@ DEFINE_EXPECT(SetScriptState_DISCONNECTED); DEFINE_EXPECT(AddNamedItem); DEFINE_EXPECT(ParseScriptText); DEFINE_EXPECT(GetScriptDispatch); +DEFINE_EXPECT(funcDisp); #define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}" @@ -167,6 +171,145 @@ static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = { static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl }; +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 + 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_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; +} + +static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI funcDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(funcDisp); + + ok(id == DISPID_VALUE, "id = %d\n", id); + ok(lcid == 0, "lcid = %x\n", lcid); + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pdp->cArgs == 2, "pdp->cArgs = %d\n", pdp->cArgs); + ok(pdp->cNamedArgs == 1, "pdp->cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pdp->rgdispidNamedArgs[0] == DISPID_THIS, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]); + ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_VT(pdp->rgvarg+1) == VT_BOOL, "V_VT(rgvarg[1]) = %d\n", V_VT(pdp->rgvarg)); + ok(V_BOOL(pdp->rgvarg+1) == VARIANT_TRUE, "V_BOOL(rgvarg[1]) = %x\n", V_BOOL(pdp->rgvarg)); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + ok(!pspCaller, "pspCaller != NULL\n"); + + V_VT(pvarRes) = VT_I4; + V_I4(pvarRes) = 100; + return S_OK; +} + +static IDispatchExVtbl testObjVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + funcDisp_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx funcDisp = { &testObjVtbl }; + static IHTMLDocument2 *create_document(void) { IHTMLDocument2 *doc; @@ -234,6 +377,10 @@ static IHTMLDocument2 *create_and_load_doc(const char *str) ULONG ref; MSG msg; HRESULT hres; + static const WCHAR ucPtr[] = {'b','a','c','k','g','r','o','u','n','d',0}; + DISPID dispID = -1; + OLECHAR *name; + doc = create_doc_with_string(str); do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink); @@ -253,6 +400,12 @@ static IHTMLDocument2 *create_and_load_doc(const char *str) return NULL; } + /* Check we can query for function on the IHTMLElementBody interface */ + name = (WCHAR*)ucPtr; + hres = IHTMLElement_GetIDsOfNames(body, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispID); + ok(hres == S_OK, "GetIDsOfNames(background) failed %08x\n", hres); + ok(dispID == DISPID_IHTMLBODYELEMENT_BACKGROUND, "Incorrect dispID got (%d)\n", dispID); + IHTMLElement_Release(body); return doc; } @@ -440,7 +593,7 @@ static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *ifac { IDispatchEx *document; IUnknown *unk; - VARIANT var; + VARIANT var, arg; DISPPARAMS dp; EXCEPINFO ei; DISPID id, named_arg = DISPID_PROPERTYPUT; @@ -449,6 +602,7 @@ static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *ifac static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0}; static const WCHAR testW[] = {'t','e','s','t',0}; + static const WCHAR funcW[] = {'f','u','n','c',0}; CHECK_EXPECT(ParseScriptText); @@ -512,13 +666,46 @@ static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *ifac ok(V_VT(&var) == VT_I4, "V_VT(var)=%d\n", V_VT(&var)); ok(V_I4(&var) == 100, "V_I4(&var) == NULL\n"); - IDispatchEx_Release(document); - unk = (void*)0xdeadbeef; hres = IDispatchEx_GetNameSpaceParent(window_dispex, &unk); ok(hres == S_OK, "GetNameSpaceParent failed: %08x\n", hres); ok(!unk, "unk=%p, expected NULL\n", unk); + id = 0; + tmp = SysAllocString(funcW); + hres = IDispatchEx_GetDispID(document, tmp, fdexNameCaseSensitive|fdexNameEnsure, &id); + SysFreeString(tmp); + ok(hres == S_OK, "GetDispID(func) failed: %08x\n", hres); + ok(id, "id == 0\n"); + + dp.cArgs = 1; + dp.rgvarg = &var; + dp.cNamedArgs = 0; + dp.rgdispidNamedArgs = NULL; + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = (IDispatch*)&funcDisp; + + hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_PROPERTYPUT, &dp, NULL, &ei, NULL); + ok(hres == S_OK, "InvokeEx failed: %08x\n", hres); + + VariantInit(&var); + memset(&dp, 0, sizeof(dp)); + memset(&ei, 0, sizeof(ei)); + V_VT(&arg) = VT_BOOL; + V_BOOL(&arg) = VARIANT_TRUE; + dp.cArgs = 1; + dp.rgvarg = &arg; + + SET_EXPECT(funcDisp); + hres = IDispatchEx_InvokeEx(document, id, LOCALE_NEUTRAL, INVOKE_FUNC, &dp, &var, &ei, NULL); + CHECK_CALLED(funcDisp); + + ok(hres == S_OK, "InvokeEx(INVOKE_FUNC) failed: %08x\n", hres); + ok(V_VT(&var) == VT_I4, "V_VT(var)=%d\n", V_VT(&var)); + ok(V_I4(&var) == 100, "V_I4(&var) == NULL\n"); + + IDispatchEx_Release(document); + return S_OK; } @@ -580,6 +767,8 @@ static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveSc { IActiveScriptSiteInterruptPoll *poll; IActiveScriptSiteDebug *debug; + IServiceProvider *service; + ICanHandleException *canexpection; LCID lcid; HRESULT hres; @@ -603,6 +792,14 @@ static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveSc if(SUCCEEDED(hres)) IActiveScriptSiteDebug32_Release(debug); + hres = IActiveScriptSite_QueryInterface(pass, &IID_ICanHandleException, (void**)&canexpection); + ok(hres == E_NOINTERFACE, "Could not get IID_ICanHandleException interface: %08x\n", hres); + + hres = IActiveScriptSite_QueryInterface(pass, &IID_IServiceProvider, (void**)&service); + todo_wine ok(hres == S_OK, "Could not get IServiceProvider interface: %08x\n", hres); + if(SUCCEEDED(hres)) + IServiceProvider_Release(service); + site = pass; IActiveScriptSite_AddRef(site); return S_OK; @@ -940,16 +1137,41 @@ static void gecko_installer_workaround(BOOL disable) 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(script) { gecko_installer_workaround(TRUE); CoInitialize(NULL); - if(register_script_engine()) { - test_simple_script(); - init_registry(FALSE); + if(winetest_interactive || ! is_ie_hardened()) { + if(register_script_engine()) { + test_simple_script(); + init_registry(FALSE); + }else { + skip("Could not register TestScript engine\n"); + } }else { - skip("Could not register TestScript engine\n"); + skip("IE running in Enhanced Security Configuration\n"); } CoUninitialize(); diff --git a/rostests/winetests/shdocvw/intshcut.c b/rostests/winetests/shdocvw/intshcut.c new file mode 100644 index 00000000000..cf0b2251b93 --- /dev/null +++ b/rostests/winetests/shdocvw/intshcut.c @@ -0,0 +1,224 @@ +/* + * Unit tests to document InternetShortcut's behaviour + * + * Copyright 2008 Damjan Jovanovic + * + * 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 + */ + +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winerror.h" + +#include "shlobj.h" +#include "shobjidl.h" +#include "shlguid.h" +#include "ole2.h" +#include "initguid.h" +#include "isguids.h" +#include "intshcut.h" + +#include "wine/test.h" + +static HRESULT WINAPI Unknown_QueryInterface(IUnknown *pUnknown, REFIID riid, void **ppvObject) +{ + if (IsEqualGUID(&IID_IUnknown, riid)) + { + *ppvObject = pUnknown; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI Unknown_AddRef(IUnknown *pUnknown) +{ + return 2; +} + +static ULONG WINAPI Unknown_Release(IUnknown *pUnknown) +{ + return 1; +} + +static IUnknownVtbl unknownVtbl = { + Unknown_QueryInterface, + Unknown_AddRef, + Unknown_Release +}; + +static IUnknown unknown = { + &unknownVtbl +}; + +static const char *printGUID(const GUID *guid) +{ + static char guidSTR[39]; + + if (!guid) return NULL; + + sprintf(guidSTR, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + return guidSTR; +} + +static void test_Aggregability(void) +{ + HRESULT hr; + IUnknown *pUnknown = NULL; + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown); + ok(SUCCEEDED(hr), "could not create instance of CLSID_InternetShortcut with IID_IUnknown, hr = 0x%x\n", hr); + if (pUnknown) + IUnknown_Release(pUnknown); + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&pUnknown); + ok(SUCCEEDED(hr), "could not create instance of CLSID_InternetShortcut with IID_IUniformResourceLocatorA, hr = 0x%x\n", hr); + if (pUnknown) + IUnknown_Release(pUnknown); + + hr = CoCreateInstance(&CLSID_InternetShortcut, &unknown, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown); + ok(FAILED(hr), "aggregation didn't fail like it should, hr = 0x%x\n", hr); + if (pUnknown) + IUnknown_Release(pUnknown); +} + +static void can_query_interface(IUnknown *pUnknown, REFIID riid) +{ + HRESULT hr; + IUnknown *newInterface; + hr = IUnknown_QueryInterface(pUnknown, riid, (void**)&newInterface); + ok(SUCCEEDED(hr), "interface %s could not be queried\n", printGUID(riid)); + if (SUCCEEDED(hr)) + IUnknown_Release(newInterface); +} + +static void test_QueryInterface(void) +{ + HRESULT hr; + IUnknown *pUnknown; + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown); + if (SUCCEEDED(hr)) + { + can_query_interface(pUnknown, &IID_IUniformResourceLocatorA); + can_query_interface(pUnknown, &IID_IUniformResourceLocatorW); + can_query_interface(pUnknown, &IID_IPersistFile); + IUnknown_Release(pUnknown); + } + else + skip("could not create a CLSID_InternetShortcut for QueryInterface tests, hr=0x%x\n", hr); +} + +static CHAR *set_and_get_url(IUniformResourceLocatorA *urlA, LPCSTR input, DWORD flags) +{ + HRESULT hr; + hr = urlA->lpVtbl->SetURL(urlA, input, flags); + if (SUCCEEDED(hr)) + { + CHAR *output; + hr = urlA->lpVtbl->GetURL(urlA, &output); + if (SUCCEEDED(hr)) + return output; + else + skip("GetUrl failed, hr=0x%x\n", hr); + } + else + skip("SetUrl (%s, 0x%x) failed, hr=0x%x\n", input, flags, hr); + return NULL; +} + +static void check_string_transform(IUniformResourceLocatorA *urlA, LPCSTR input, DWORD flags, LPCSTR expectedOutput) +{ + CHAR *output = set_and_get_url(urlA, input, flags); + if (output != NULL) + { + ok(lstrcmpA(output, expectedOutput) == 0, "unexpected URL change %s -> %s (expected %s)\n", + input, output, expectedOutput); + CoTaskMemFree(output); + } +} + +static void test_NullURLs(void) +{ + HRESULT hr; + IUniformResourceLocatorA *urlA; + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA); + if (SUCCEEDED(hr)) + { + LPSTR url = NULL; + + hr = urlA->lpVtbl->GetURL(urlA, &url); + ok(SUCCEEDED(hr), "getting uninitialized URL unexpectedly failed, hr=0x%x\n", hr); + ok(url == NULL, "uninitialized URL is not NULL but %s\n", url); + + hr = urlA->lpVtbl->SetURL(urlA, NULL, 0); + ok(SUCCEEDED(hr), "setting NULL URL unexpectedly failed, hr=0x%x\n", hr); + + hr = urlA->lpVtbl->GetURL(urlA, &url); + ok(SUCCEEDED(hr), "getting NULL URL unexpectedly failed, hr=0x%x\n", hr); + ok(url == NULL, "URL unexpectedly not NULL but %s\n", url); + + urlA->lpVtbl->Release(urlA); + } + else + skip("could not create a CLSID_InternetShortcut for NullURL tests, hr=0x%x\n", hr); +} + +static void test_SetURLFlags(void) +{ + HRESULT hr; + IUniformResourceLocatorA *urlA; + + hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_ALL, &IID_IUniformResourceLocatorA, (void**)&urlA); + if (SUCCEEDED(hr)) + { + check_string_transform(urlA, "somerandomstring", 0, "somerandomstring"); + check_string_transform(urlA, "www.winehq.org", 0, "www.winehq.org"); + + todo_wine + { + check_string_transform(urlA, "www.winehq.org", IURL_SETURL_FL_GUESS_PROTOCOL, "http://www.winehq.org/"); + check_string_transform(urlA, "ftp.winehq.org", IURL_SETURL_FL_GUESS_PROTOCOL, "ftp://ftp.winehq.org/"); + } + + urlA->lpVtbl->Release(urlA); + } + else + skip("could not create a CLSID_InternetShortcut for SetUrl tests, hr=0x%x\n", hr); +} + +static void test_InternetShortcut(void) +{ + test_Aggregability(); + test_QueryInterface(); + test_NullURLs(); + test_SetURLFlags(); +} + +START_TEST(intshcut) +{ + OleInitialize(NULL); + test_InternetShortcut(); + OleUninitialize(); +} diff --git a/rostests/winetests/shdocvw/shdocvw.c b/rostests/winetests/shdocvw/shdocvw.c new file mode 100644 index 00000000000..8e7b1f3d213 --- /dev/null +++ b/rostests/winetests/shdocvw/shdocvw.c @@ -0,0 +1,360 @@ +/* + * Unit tests for misc shdocvw functions + * + * Copyright 2008 Detlef Riekenberg + * + * 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 + */ + + +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wininet.h" +#include "winnls.h" + +#include "wine/test.h" + +/* ################ */ + +static HMODULE hshdocvw; +static HRESULT (WINAPI *pURLSubRegQueryA)(LPCSTR, LPCSTR, DWORD, LPVOID, DWORD, DWORD); +static DWORD (WINAPI *pParseURLFromOutsideSourceA)(LPCSTR, LPSTR, LPDWORD, LPDWORD); +static DWORD (WINAPI *pParseURLFromOutsideSourceW)(LPCWSTR, LPWSTR, LPDWORD, LPDWORD); + +static CHAR appdata[] = "AppData"; +static CHAR common_appdata[] = "Common AppData"; +static CHAR default_page_url[] = "Default_Page_URL"; +static CHAR does_not_exist[] = "does_not_exist"; +static CHAR regpath_iemain[] = "Software\\Microsoft\\Internet Explorer\\Main"; +static CHAR regpath_shellfolders[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; +static CHAR start_page[] = "Start Page"; + +/* ################ */ + +static const struct { + const char *url; + const char *newurl; + DWORD len; +} ParseURL_table[] = { + {"http://www.winehq.org", "http://www.winehq.org/", 22}, + {"www.winehq.org", "http://www.winehq.org/", 22}, + {"winehq.org", "http://winehq.org/", 18}, + {"ftp.winehq.org", "ftp://ftp.winehq.org/", 21}, + {"http://winehq.org", "http://winehq.org/", 18}, + {"https://winehq.org", "https://winehq.org/", 19}, + {"https://www.winehq.org", "https://www.winehq.org/", 23}, + {"ftp://winehq.org", "ftp://winehq.org/", 17}, + {"ftp://ftp.winehq.org", "ftp://ftp.winehq.org/", 21}, + {"about:blank", "about:blank", 11}, + {"about:home", "about:home", 10}, + {"about:mozilla", "about:mozilla", 13}, + /* a space at the start is not allowed */ + {" http://www.winehq.org", "http://%20http://www.winehq.org", 31} + +}; + +/* ################ */ + +static void init_functions(void) +{ + hshdocvw = LoadLibraryA("shdocvw.dll"); + pURLSubRegQueryA = (void *) GetProcAddress(hshdocvw, (LPSTR) 151); + pParseURLFromOutsideSourceA = (void *) GetProcAddress(hshdocvw, (LPSTR) 169); + pParseURLFromOutsideSourceW = (void *) GetProcAddress(hshdocvw, (LPSTR) 170); +} + +/* ################ */ + +static void test_URLSubRegQueryA(void) +{ + CHAR buffer[INTERNET_MAX_URL_LENGTH]; + HRESULT hr; + DWORD used; + DWORD len; + + if (!pURLSubRegQueryA) { + skip("URLSubRegQueryA not found\n"); + return; + } + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + /* called by inetcpl.cpl */ + hr = pURLSubRegQueryA(regpath_iemain, default_page_url, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + ok(hr == E_FAIL || hr == S_OK, "got 0x%x (expected E_FAIL or S_OK)\n", hr); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + /* called by inetcpl.cpl */ + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + len = lstrlenA(buffer); + /* respect privacy: do not dump the url */ + ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, len); + + /* test buffer length: just large enough */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len+1, -1); + used = lstrlenA(buffer); + /* respect privacy: do not dump the url */ + ok((hr == S_OK) && (used == len), + "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len); + + /* no space for terminating 0: result is truncated */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len, -1); + used = lstrlenA(buffer); + ok((hr == S_OK) && (used == len - 1), + "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len - 1); + + /* no space for the complete result: truncate another char */ + if (len > 1) { + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, len-1, -1); + used = lstrlenA(buffer); + ok((hr == S_OK) && (used == (len - 2)), + "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len - 2); + } + + /* only space for the terminating 0: function still succeded */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, 1, -1); + used = lstrlenA(buffer); + ok((hr == S_OK) && !used, + "got 0x%x and %d (expected S_OK and 0)\n", hr, used); + + /* size of buffer is 0, but the function still succeed. + buffer[0] is cleared in IE 5.01 and IE 5.5 (Buffer Overflow) */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, buffer, 0, -1); + used = lstrlenA(buffer); + ok( (hr == S_OK) && + ((used == INTERNET_MAX_URL_LENGTH - 1) || broken(used == 0)) , + "got 0x%x and %d (expected S_OK and INTERNET_MAX_URL_LENGTH - 1)\n", + hr, used); + + /* still succeed without a buffer for the result */ + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, NULL, 0, -1); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + + /* still succeed, when a length is given without a buffer */ + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_SZ, NULL, INTERNET_MAX_URL_LENGTH, -1); + ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); + + /* this value does not exist */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, does_not_exist, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + /* random bytes are copied to the buffer */ + ok((hr == E_FAIL), "got 0x%x (expected E_FAIL)\n", hr); + + /* the third parameter is ignored. Is it really a type? (data is REG_SZ) */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_iemain, start_page, REG_DWORD, buffer, INTERNET_MAX_URL_LENGTH, -1); + used = lstrlenA(buffer); + ok((hr == S_OK) && (used == len), + "got 0x%x and %d (expected S_OK and %d)\n", hr, used, len); + + /* the function works for HKCU and HKLM */ + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_shellfolders, appdata, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + used = lstrlenA(buffer); + ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, used); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + hr = pURLSubRegQueryA(regpath_shellfolders, common_appdata, REG_SZ, buffer, INTERNET_MAX_URL_LENGTH, -1); + used = lstrlenA(buffer); + ok(hr == S_OK, "got 0x%x and %d (expected S_OK)\n", hr, used); + + /* todo: what does the last parameter mean? */ +} + +/* ################ */ + +static void test_ParseURLFromOutsideSourceA(void) +{ + CHAR buffer[INTERNET_MAX_URL_LENGTH]; + DWORD dummy; + DWORD maxlen; + DWORD len; + DWORD res; + int i; + + if (!pParseURLFromOutsideSourceA) { + skip("ParseURLFromOutsideSourceA not found\n"); + return; + } + + for(i = 0; i < sizeof(ParseURL_table)/sizeof(ParseURL_table[0]); i++) { + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = sizeof(buffer); + dummy = 0; + /* on success, len+1 is returned. No idea, if someone depend on this */ + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); + /* len does not include the terminating 0, when buffer is large enough */ + ok( res != 0 && len == ParseURL_table[i].len && + !lstrcmpA(buffer, ParseURL_table[i].newurl), + "#%d: got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + i, res, len, buffer, ParseURL_table[i].len, ParseURL_table[i].newurl); + + + /* use the size test only for the first examples */ + if (i > 4) continue; + + maxlen = len; + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen + 1; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); + ok( res != 0 && len == ParseURL_table[i].len && + !lstrcmpA(buffer, ParseURL_table[i].newurl), + "#%d (+1): got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + i, res, len, buffer, ParseURL_table[i].len, ParseURL_table[i].newurl); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); + /* len includes the terminating 0, when the buffer is too small */ + ok( res == 0 && len == ParseURL_table[i].len + 1, + "#%d (==): got %d and %d (expected '0' and %d)\n", + i, res, len, ParseURL_table[i].len + 1); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen-1; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, &dummy); + /* len includes the terminating 0 on XP SP1 and before, when the buffer is too small */ + ok( res == 0 && (len == ParseURL_table[i].len || len == ParseURL_table[i].len + 1), + "#%d (-1): got %d and %d (expected '0' and %d or %d)\n", + i, res, len, ParseURL_table[i].len, ParseURL_table[i].len + 1); + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen+1; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, NULL, &len, &dummy); + /* len does not include the terminating 0, when buffer is NULL */ + ok( res == 0 && len == ParseURL_table[i].len, + "#%d (buffer): got %d and %d (expected '0' and %d)\n", + i, res, len, ParseURL_table[i].len); + + if (0) { + /* that test crash on native shdocvw */ + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, NULL, &dummy); + } + + memset(buffer, '#', sizeof(buffer)-1); + buffer[sizeof(buffer)-1] = '\0'; + len = maxlen+1; + dummy = 0; + res = pParseURLFromOutsideSourceA(ParseURL_table[i].url, buffer, &len, NULL); + ok( res != 0 && len == ParseURL_table[i].len && + !lstrcmpA(buffer, ParseURL_table[i].newurl), + "#%d (unknown): got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + i, res, len, buffer, ParseURL_table[i].len, ParseURL_table[i].newurl); + } +} + +/* ################ */ + +static void test_ParseURLFromOutsideSourceW(void) +{ + WCHAR urlW[INTERNET_MAX_URL_LENGTH]; + WCHAR bufferW[INTERNET_MAX_URL_LENGTH]; + CHAR bufferA[INTERNET_MAX_URL_LENGTH]; + DWORD maxlen; + DWORD dummy; + DWORD len; + DWORD res; + + if (!pParseURLFromOutsideSourceW) { + skip("ParseURLFromOutsideSourceW not found\n"); + return; + } + MultiByteToWideChar(CP_ACP, 0, ParseURL_table[0].url, -1, urlW, INTERNET_MAX_URL_LENGTH); + + memset(bufferA, '#', sizeof(bufferA)-1); + bufferA[sizeof(bufferA) - 1] = '\0'; + MultiByteToWideChar(CP_ACP, 0, bufferA, -1, bufferW, INTERNET_MAX_URL_LENGTH); + + /* len is in characters */ + len = sizeof(bufferW)/sizeof(bufferW[0]); + dummy = 0; + res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL); + ok( res != 0 && len == ParseURL_table[0].len && + !lstrcmpA(bufferA, ParseURL_table[0].newurl), + "got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + res, len, bufferA, ParseURL_table[0].len, ParseURL_table[0].newurl); + + + maxlen = len; + + memset(bufferA, '#', sizeof(bufferA)-1); + bufferA[sizeof(bufferA) - 1] = '\0'; + MultiByteToWideChar(CP_ACP, 0, bufferA, -1, bufferW, INTERNET_MAX_URL_LENGTH); + len = maxlen+1; + dummy = 0; + res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); + WideCharToMultiByte(CP_ACP, 0, bufferW, -1, bufferA, sizeof(bufferA), NULL, NULL); + /* len does not include the terminating 0, when buffer is large enough */ + ok( res != 0 && len == ParseURL_table[0].len && + !lstrcmpA(bufferA, ParseURL_table[0].newurl), + "+1: got %d and %d with '%s' (expected '!=0' and %d with '%s')\n", + res, len, bufferA, ParseURL_table[0].len, ParseURL_table[0].newurl); + + len = maxlen; + dummy = 0; + res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); + /* len includes the terminating 0, when the buffer is too small */ + ok( res == 0 && len == ParseURL_table[0].len + 1, + "==: got %d and %d (expected '0' and %d)\n", + res, len, ParseURL_table[0].len + 1); + + len = maxlen - 1; + dummy = 0; + res = pParseURLFromOutsideSourceW(urlW, bufferW, &len, &dummy); + /* len includes the terminating 0 on XP SP1 and before, when the buffer is too small */ + ok( res == 0 && (len == ParseURL_table[0].len || len == ParseURL_table[0].len + 1), + "-1: got %d and %d (expected '0' and %d or %d)\n", + res, len, ParseURL_table[0].len, ParseURL_table[0].len + 1); + +} + +/* ################ */ + +START_TEST(shdocvw) +{ + init_functions(); + test_URLSubRegQueryA(); + test_ParseURLFromOutsideSourceA(); + test_ParseURLFromOutsideSourceW(); +} diff --git a/rostests/winetests/shdocvw/shdocvw.rbuild b/rostests/winetests/shdocvw/shdocvw.rbuild new file mode 100644 index 00000000000..ef90f60e4aa --- /dev/null +++ b/rostests/winetests/shdocvw/shdocvw.rbuild @@ -0,0 +1,23 @@ + + + + + -Wno-format + . + + intshcut.c + shdocvw.c + shortcut.c + webbrowser.c + testlist.c + wine + gdi32 + shell32 + ole32 + oleaut32 + user32 + advapi32 + kernel32 + ntdll + + diff --git a/rostests/winetests/shdocvw/shortcut.c b/rostests/winetests/shdocvw/shortcut.c new file mode 100644 index 00000000000..5a740dc7dfd --- /dev/null +++ b/rostests/winetests/shdocvw/shortcut.c @@ -0,0 +1,231 @@ +/* + * Unit tests to document shdocvw's 'Shell Instance Objects' features + * + * Copyright 2005 Michael Jung + * + * 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 + */ + +/* At least since Windows 2000 it's possible to add FolderShortcut objects + * by creating some registry entries. Those objects, which refer to some + * point in the filesystem, can be registered in the shell namespace like other + * shell namespace extensions. Icons, names and filesystem location can be + * configured. This is documented at http://www.virtualplastic.net/html/ui_shell.html + * You can also google for a tool called "ShellObjectEditor" by "Tropical + * Technologies". This mechanism would be cool for wine, since we could + * map Gnome's virtual devices to FolderShortcuts and have them appear in the + * file dialogs. These unit tests are meant to document how this mechanism + * works on windows. + * + * Search MSDN for "Creating Shell Extensions with Shell Instance Objects" for + * more documentation.*/ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" + +#include "shlobj.h" +#include "shobjidl.h" +#include "shlguid.h" +#include "ole2.h" + +#include "wine/test.h" + +/* The following definitions and helper functions are meant to make the de-/registration + * of the various necessary registry keys easier. */ + +struct registry_value { + const char *szName; + const DWORD dwType; + const char *szValue; + const DWORD dwValue; +}; + +#define REG_VALUE_ADDR(x) ((x->dwType==REG_SZ)?(const BYTE *)x->szValue:(const BYTE *)&x->dwValue) +#define REG_VALUE_SIZE(x) ((x->dwType==REG_SZ)?strlen(x->szValue)+1:sizeof(DWORD)) + +struct registry_key { + const char *szName; + const struct registry_value *pValues; + const unsigned int cValues; + const struct registry_key *pSubKeys; + const unsigned int cSubKeys; +}; + +static const struct registry_value ShellFolder_values[] = { + { "WantsFORPARSING", REG_SZ, "", 0 }, + { "Attributes", REG_DWORD, NULL, 0xF8000100 } +}; + +static const struct registry_value Instance_values[] = { + { "CLSID", REG_SZ, "{0AFACED1-E828-11D1-9187-B532F1E9575D}", 0 } +}; + +static const struct registry_value InitPropertyBag_values[] = { + { "Attributes", REG_DWORD, NULL, 0x00000015 }, + { "Target", REG_SZ, "C:\\", 0 } +}; + +static const struct registry_key Instance_keys[] = { + { "InitPropertyBag", InitPropertyBag_values, 2, NULL, 0 } +}; + +static const struct registry_value InProcServer32_values[] = { + { NULL, REG_SZ, "shdocvw.dll", 0 }, + { "ThreadingModel", REG_SZ, "Apartment", 0 } +}; + +static const struct registry_value DefaultIcon_values[] = { + { NULL, REG_SZ,"shell32.dll,8", 0 } +}; + +static const struct registry_key ShortcutCLSID_keys[] = { + { "DefaultIcon", DefaultIcon_values, 1, NULL, 0 }, + { "InProcServer32", InProcServer32_values, 2, NULL, 0 }, + { "Instance", Instance_values, 1, Instance_keys, 1 }, + { "ShellFolder", ShellFolder_values, 2, NULL, 0 } +}; + +static const struct registry_value ShortcutCLSID_values[] = { + { NULL, REG_SZ, "WineTest", 0 } +}; + +static const struct registry_key HKEY_CLASSES_ROOT_keys[] = { + { "CLSID\\{9B352EBF-2765-45C1-B4C6-85CC7F7ABC64}", ShortcutCLSID_values, 1, ShortcutCLSID_keys, 4} +}; + +/* register_keys - helper function, which recursively creates the registry keys and values in + * parameter 'keys' in the registry under hRootKey. */ +static BOOL register_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys) { + HKEY hKey; + unsigned int iKey, iValue; + + for (iKey = 0; iKey < numKeys; iKey++) { + if (ERROR_SUCCESS == RegCreateKeyExA(hRootKey, keys[iKey].szName, 0, NULL, 0, + KEY_WRITE, NULL, &hKey, NULL)) + { + for (iValue = 0; iValue < keys[iKey].cValues; iValue++) { + const struct registry_value * value = &keys[iKey].pValues[iValue]; + if (ERROR_SUCCESS != RegSetValueExA(hKey, value->szName, 0, value->dwType, + REG_VALUE_ADDR(value), REG_VALUE_SIZE(value))) + { + RegCloseKey(hKey); + return FALSE; + } + } + + if (!register_keys(hKey, keys[iKey].pSubKeys, keys[iKey].cSubKeys)) { + RegCloseKey(hKey); + return FALSE; + } + + RegCloseKey(hKey); + } + } + + return TRUE; +} + +/* unregister_keys - clean up after register_keys */ +static void unregister_keys(HKEY hRootKey, const struct registry_key *keys, unsigned int numKeys) { + HKEY hKey; + unsigned int iKey; + + for (iKey = 0; iKey < numKeys; iKey++) { + if (ERROR_SUCCESS == RegOpenKeyExA(hRootKey, keys[iKey].szName, 0, DELETE, &hKey)) { + unregister_keys(hKey, keys[iKey].pSubKeys, keys[iKey].cSubKeys); + RegCloseKey(hKey); + } + RegDeleteKeyA(hRootKey, keys[iKey].szName); + } +} + +static void test_ShortcutFolder(void) { + LPSHELLFOLDER pDesktopFolder, pWineTestFolder; + IPersistFolder3 *pWineTestPersistFolder; + LPITEMIDLIST pidlWineTestFolder, pidlCurFolder; + HRESULT hr; + CLSID clsid; + const CLSID CLSID_WineTest = + { 0x9b352ebf, 0x2765, 0x45c1, { 0xb4, 0xc6, 0x85, 0xcc, 0x7f, 0x7a, 0xbc, 0x64 } }; + WCHAR wszWineTestFolder[] = { + ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-', + 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 }; + + /* First, we register all the necessary registry keys/values for our 'WineTest' + * shell object. */ + register_keys(HKEY_CLASSES_ROOT, HKEY_CLASSES_ROOT_keys, 1); + + hr = SHGetDesktopFolder(&pDesktopFolder); + ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr); + if (FAILED(hr)) goto cleanup; + + /* Convert the wszWineTestFolder string to an ITEMIDLIST. */ + hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL, + &pidlWineTestFolder, NULL); + todo_wine + { + ok (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), + "Expected %08x, got %08x\n", HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), hr); + } + if (FAILED(hr)) { + IShellFolder_Release(pDesktopFolder); + goto cleanup; + } + + /* FIXME: these tests are never run */ + + /* Bind to a WineTest folder object. There has to be some support for this in shdocvw.dll. + * This isn't implemented in wine yet.*/ + hr = IShellFolder_BindToObject(pDesktopFolder, pidlWineTestFolder, NULL, &IID_IShellFolder, + (LPVOID*)&pWineTestFolder); + IShellFolder_Release(pDesktopFolder); + ILFree(pidlWineTestFolder); + ok (SUCCEEDED(hr), "IShellFolder::BindToObject(WineTestFolder) failed! hr = %08x\n", hr); + if (FAILED(hr)) goto cleanup; + + hr = IShellFolder_QueryInterface(pWineTestFolder, &IID_IPersistFolder3, (LPVOID*)&pWineTestPersistFolder); + ok (SUCCEEDED(hr), "IShellFolder::QueryInterface(IPersistFolder3) failed! hr = %08x\n", hr); + IShellFolder_Release(pWineTestFolder); + if (FAILED(hr)) goto cleanup; + + /* The resulting folder object has the FolderShortcut CLSID, instead of it's own. */ + hr = IPersistFolder3_GetClassID(pWineTestPersistFolder, &clsid); + ok (SUCCEEDED(hr), "IPersist::GetClassID failed! hr = %08x\n", hr); + ok (IsEqualCLSID(&CLSID_FolderShortcut, &clsid), "GetClassId returned wrong CLSID!\n"); + + pidlCurFolder = (LPITEMIDLIST)0xdeadbeef; + hr = IPersistFolder3_GetCurFolder(pWineTestPersistFolder, &pidlCurFolder); + ok (SUCCEEDED(hr), "IPersistFolder3::GetCurFolder failed! hr = %08x\n", hr); + ok (pidlCurFolder->mkid.cb == 20 && ((LPSHITEMID)((BYTE*)pidlCurFolder+20))->cb == 0 && + IsEqualCLSID(&CLSID_WineTest, (REFCLSID)((LPBYTE)pidlCurFolder+4)), + "GetCurFolder returned unexpected pidl!\n"); + + IPersistFolder3_Release(pWineTestPersistFolder); + +cleanup: + unregister_keys(HKEY_CLASSES_ROOT, HKEY_CLASSES_ROOT_keys, 1); +} + +START_TEST(shortcut) +{ + OleInitialize(NULL); + test_ShortcutFolder(); + OleUninitialize(); +} diff --git a/rostests/winetests/shdocvw/testlist.c b/rostests/winetests/shdocvw/testlist.c new file mode 100644 index 00000000000..18ce563f47a --- /dev/null +++ b/rostests/winetests/shdocvw/testlist.c @@ -0,0 +1,22 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include + +#define STANDALONE +#include "wine/test.h" + +extern void func_intshcut(void); +extern void func_shdocvw(void); +extern void func_shortcut(void); +extern void func_protocol(void); +extern void func_webbrowser(void); + +const struct test winetest_testlist[] = +{ + { "intshcut", func_intshcut }, + { "shdocvw", func_shdocvw }, + { "shortcut", func_shortcut }, + { "webbrowser", func_webbrowser }, + { 0, 0 } +}; diff --git a/rostests/winetests/shdocvw/webbrowser.c b/rostests/winetests/shdocvw/webbrowser.c new file mode 100644 index 00000000000..5b041195823 --- /dev/null +++ b/rostests/winetests/shdocvw/webbrowser.c @@ -0,0 +1,2137 @@ +/* + * Copyright 2006 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 "initguid.h" +#include "ole2.h" +#include "exdisp.h" +#include "htiframe.h" +#include "mshtmhst.h" +#include "idispids.h" +#include "olectl.h" +#include "mshtmdid.h" +#include "shobjidl.h" +#include "shlguid.h" +#include "exdispid.h" + +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + 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 CHECK_CALLED_BROKEN(func) \ + do { \ + ok(called_ ## func || broken(!called_ ## func), "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(GetContainer); +DEFINE_EXPECT(Site_GetWindow); +DEFINE_EXPECT(ShowObject); +DEFINE_EXPECT(CanInPlaceActivate); +DEFINE_EXPECT(OnInPlaceActivate); +DEFINE_EXPECT(OnUIActivate); +DEFINE_EXPECT(GetWindowContext); +DEFINE_EXPECT(Frame_GetWindow); +DEFINE_EXPECT(Frame_SetActiveObject); +DEFINE_EXPECT(UIWindow_SetActiveObject); +DEFINE_EXPECT(SetMenu); +DEFINE_EXPECT(Invoke_AMBIENT_USERMODE); +DEFINE_EXPECT(Invoke_AMBIENT_DLCONTROL); +DEFINE_EXPECT(Invoke_AMBIENT_USERAGENT); +DEFINE_EXPECT(Invoke_AMBIENT_PALETTE); +DEFINE_EXPECT(Invoke_AMBIENT_SILENT); +DEFINE_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); +DEFINE_EXPECT(Invoke_STATUSTEXTCHANGE); +DEFINE_EXPECT(Invoke_PROPERTYCHANGE); +DEFINE_EXPECT(Invoke_DOWNLOADBEGIN); +DEFINE_EXPECT(Invoke_BEFORENAVIGATE2); +DEFINE_EXPECT(Invoke_SETSECURELOCKICON); +DEFINE_EXPECT(Invoke_FILEDOWNLOAD); +DEFINE_EXPECT(Invoke_COMMANDSTATECHANGE); +DEFINE_EXPECT(Invoke_DOWNLOADCOMPLETE); +DEFINE_EXPECT(Invoke_ONMENUBAR); +DEFINE_EXPECT(Invoke_ONADDRESSBAR); +DEFINE_EXPECT(Invoke_ONSTATUSBAR); +DEFINE_EXPECT(Invoke_ONTOOLBAR); +DEFINE_EXPECT(Invoke_ONFULLSCREEN); +DEFINE_EXPECT(Invoke_ONTHEATERMODE); +DEFINE_EXPECT(Invoke_WINDOWSETRESIZABLE); +DEFINE_EXPECT(EnableModeless_TRUE); +DEFINE_EXPECT(EnableModeless_FALSE); +DEFINE_EXPECT(GetHostInfo); +DEFINE_EXPECT(GetOptionKeyPath); +DEFINE_EXPECT(GetOverridesKeyPath); +DEFINE_EXPECT(SetStatusText); +DEFINE_EXPECT(UpdateUI); +DEFINE_EXPECT(Exec_SETDOWNLOADSTATE_0); +DEFINE_EXPECT(Exec_SETDOWNLOADSTATE_1); +DEFINE_EXPECT(Exec_SETPROGRESSMAX); +DEFINE_EXPECT(Exec_SETPROGRESSPOS); +DEFINE_EXPECT(QueryStatus_SETPROGRESSTEXT); + +static const WCHAR wszItem[] = {'i','t','e','m',0}; +static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0}; +static const WCHAR emptyW[] = {0}; + +static VARIANT_BOOL exvb; +static IWebBrowser2 *wb; + +static HWND container_hwnd, shell_embedding_hwnd; + +static const char *debugstr_w(LPCWSTR str) +{ + static char buf[1024]; + if(!str) + return "(null)"; + 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; +} + +#define test_LocationURL(a,b) _test_LocationURL(__LINE__,a,b) +static void _test_LocationURL(unsigned line, IUnknown *unk, LPCWSTR exurl) +{ + IWebBrowser2 *wb; + BSTR url = (void*)0xdeadbeef; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&wb); + ok(hres == S_OK, "Could not get IWebBrowser2 interface: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IWebBrowser2_get_LocationURL(wb, &url); + ok_(__FILE__,line) (hres == (*exurl ? S_OK : S_FALSE), "get_LocationURL failed: %08x\n", hres); + ok_(__FILE__,line) (!lstrcmpW(url, exurl), "unexpected URL: %s\n", debugstr_w(url)); + + SysFreeString(url); + IWebBrowser2_Release(wb); +} + +static HRESULT QueryInterface(REFIID,void**); + +static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, + REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface) +{ + return 2; +} + +static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface) +{ + return 1; +} + +static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +{ + ok(!pguidCmdGroup, "pguidCmdGroup != MULL\n"); + ok(cCmds == 1, "cCmds=%d, expected 1\n", cCmds); + ok(!pCmdText, "pCmdText != NULL\n"); + + switch(prgCmds[0].cmdID) { + case OLECMDID_SETPROGRESSTEXT: + CHECK_EXPECT(QueryStatus_SETPROGRESSTEXT); + prgCmds[0].cmdf = OLECMDF_ENABLED; + return S_OK; + default: + ok(0, "unexpected command %d\n", prgCmds[0].cmdID); + } + + return E_FAIL; +} + +static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + if(!pguidCmdGroup) { + switch(nCmdID) { + case OLECMDID_SETPROGRESSMAX: + CHECK_EXPECT(Exec_SETPROGRESSMAX); + ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER, "nCmdexecopts=%08x\n", nCmdexecopt); + ok(pvaIn != NULL, "pvaIn == NULL\n"); + if(pvaIn) + ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d, expected VT_I4\n", V_VT(pvaIn)); + ok(pvaOut == NULL, "pvaOut=%p, expected NULL\n", pvaOut); + return S_OK; + case OLECMDID_SETPROGRESSPOS: + CHECK_EXPECT(Exec_SETPROGRESSPOS); + ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER, "nCmdexecopts=%08x\n", nCmdexecopt); + ok(pvaIn != NULL, "pvaIn == NULL\n"); + if(pvaIn) + ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d, expected VT_I4\n", V_VT(pvaIn)); + ok(pvaOut == NULL, "pvaOut=%p, expected NULL\n", pvaOut); + return S_OK; + case OLECMDID_SETDOWNLOADSTATE: + ok(!nCmdexecopt, "nCmdexecopts=%08x\n", nCmdexecopt); + ok(pvaOut == NULL, "pvaOut=%p\n", pvaOut); + ok(pvaIn != NULL, "pvaIn == NULL\n"); + ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d\n", V_VT(pvaIn)); + switch(V_I4(pvaIn)) { + case 0: + CHECK_EXPECT(Exec_SETDOWNLOADSTATE_0); + break; + case 1: + CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_1); + break; + default: + ok(0, "unexpevted V_I4(pvaIn)=%d\n", V_I4(pvaIn)); + } + return S_OK; + default: + ok(0, "unexpected nsCmdID %d\n", nCmdID); + } + }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) { + switch(nCmdID) { + case 24: + return E_FAIL; /* TODO */ + case 25: + return E_FAIL; /* IE5 */ + case 66: + return E_FAIL; /* TODO */ + default: + ok(0, "unexpected nCmdID %d\n", nCmdID); + } + }else { + ok(0, "unepected pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup)); + } + + return E_FAIL; +} + +static IOleCommandTargetVtbl OleCommandTargetVtbl = { + OleCommandTarget_QueryInterface, + OleCommandTarget_AddRef, + OleCommandTarget_Release, + OleCommandTarget_QueryStatus, + OleCommandTarget_Exec +}; + +static IOleCommandTarget OleCommandTarget = { &OleCommandTargetVtbl }; + +static HRESULT WINAPI OleContainer_QueryInterface(IOleContainer *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_ITargetContainer, riid)) + return E_NOINTERFACE; /* TODO */ + + if(IsEqualGUID(&IID_IOleCommandTarget, riid)) { + *ppv = &OleCommandTarget; + return S_OK; + } + + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI OleContainer_AddRef(IOleContainer *iface) +{ + return 2; +} + +static ULONG WINAPI OleContainer_Release(IOleContainer *iface) +{ + return 1; +} + +static HRESULT WINAPI OleContainer_ParseDisplayName(IOleContainer *iface, IBindCtx *pbc, + LPOLESTR pszDiaplayName, ULONG *pchEaten, IMoniker **ppmkOut) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI OleContainer_EnumObjects(IOleContainer *iface, DWORD grfFlags, + IEnumUnknown **ppenum) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI OleContainer_LockContainer(IOleContainer *iface, BOOL fLock) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IOleContainerVtbl OleContainerVtbl = { + OleContainer_QueryInterface, + OleContainer_AddRef, + OleContainer_Release, + OleContainer_ParseDisplayName, + OleContainer_EnumObjects, + OleContainer_LockContainer +}; + +static IOleContainer OleContainer = { &OleContainerVtbl }; + +static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI Dispatch_AddRef(IDispatch *iface) +{ + return 2; +} + +static ULONG WINAPI Dispatch_Release(IDispatch *iface) +{ + return 1; +} + +static HRESULT WINAPI Dispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Dispatch_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Dispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(IsEqualGUID(&IID_NULL, riid), "riid != IID_NULL\n"); + ok(pDispParams != NULL, "pDispParams == NULL\n"); + ok(pExcepInfo == NULL, "pExcepInfo=%p, expected NULL\n", pExcepInfo); + ok(V_VT(pVarResult) == VT_EMPTY, "V_VT(pVarResult)=%d\n", V_VT(pVarResult)); + ok(wFlags == DISPATCH_PROPERTYGET, "wFlags=%08x, expected DISPATCH_PROPERTYGET\n", wFlags); + ok(pDispParams->rgvarg == NULL, "pDispParams->rgvarg = %p\n", pDispParams->rgvarg); + ok(pDispParams->rgdispidNamedArgs == NULL, + "pDispParams->rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs); + ok(pDispParams->cArgs == 0, "pDispParams->cArgs = %d\n", pDispParams->cArgs); + ok(pDispParams->cNamedArgs == 0, "pDispParams->cNamedArgs = %d\n", pDispParams->cNamedArgs); + + switch(dispIdMember) { + case DISPID_AMBIENT_USERMODE: + CHECK_EXPECT2(Invoke_AMBIENT_USERMODE); + return E_FAIL; + case DISPID_AMBIENT_DLCONTROL: + CHECK_EXPECT(Invoke_AMBIENT_DLCONTROL); + ok(puArgErr != NULL, "puArgErr=%p\n", puArgErr); + return E_FAIL; + case DISPID_AMBIENT_USERAGENT: + CHECK_EXPECT(Invoke_AMBIENT_USERAGENT); + ok(puArgErr != NULL, "puArgErr=%p\n", puArgErr); + return E_FAIL; + case DISPID_AMBIENT_PALETTE: + CHECK_EXPECT(Invoke_AMBIENT_PALETTE); + ok(puArgErr != NULL, "puArgErr=%p\n", puArgErr); + return E_FAIL; + case DISPID_AMBIENT_OFFLINEIFNOTCONNECTED: + CHECK_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + ok(puArgErr == NULL, "puArgErr=%p\n", puArgErr); + V_VT(pVarResult) = VT_BOOL; + V_BOOL(pVarResult) = VARIANT_FALSE; + return S_OK; + case DISPID_AMBIENT_SILENT: + CHECK_EXPECT(Invoke_AMBIENT_SILENT); + ok(puArgErr == NULL, "puArgErr=%p\n", puArgErr); + V_VT(pVarResult) = VT_BOOL; + V_BOOL(pVarResult) = VARIANT_FALSE; + return S_OK; + } + + ok(0, "unexpected dispIdMember %d\n", dispIdMember); + return E_NOTIMPL; +} + +static IDispatchVtbl DispatchVtbl = { + Dispatch_QueryInterface, + Dispatch_AddRef, + Dispatch_Release, + Dispatch_GetTypeInfoCount, + Dispatch_GetTypeInfo, + Dispatch_GetIDsOfNames, + Dispatch_Invoke +}; + +static IDispatch Dispatch = { &DispatchVtbl }; + +static HRESULT WINAPI WebBrowserEvents2_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&DIID_DWebBrowserEvents2, riid)) { + *ppv = iface; + return S_OK; + } + + ok(0, "unexpected riid %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +#define test_invoke_bool(p,s) _test_invoke_bool(__LINE__,p,s) +static void _test_invoke_bool(unsigned line, const DISPPARAMS *params, BOOL strict) +{ + ok_(__FILE__,line) (params->rgvarg != NULL, "rgvarg == NULL\n"); + ok_(__FILE__,line) (params->cArgs == 1, "cArgs=%d, expected 1\n", params->cArgs); + ok_(__FILE__,line) (V_VT(params->rgvarg) == VT_BOOL, "V_VT(arg)=%d\n", V_VT(params->rgvarg)); + if(strict) + ok_(__FILE__,line) (V_BOOL(params->rgvarg) == exvb, "V_VT(arg)=%x, expected %x\n", + V_BOOL(params->rgvarg), exvb); + else + ok_(__FILE__,line) (!V_BOOL(params->rgvarg) == !exvb, "V_VT(arg)=%x, expected %x\n", + V_BOOL(params->rgvarg), exvb); +} + +static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const VARIANT *flags, + const VARIANT *frame, const VARIANT *post_data, const VARIANT *headers, const VARIANT *cancel) +{ + ok(V_VT(disp) == VT_DISPATCH, "V_VT(disp)=%d, expected VT_DISPATCH\n", V_VT(disp)); + ok(V_DISPATCH(disp) != NULL, "V_DISPATCH(disp) == NULL\n"); + ok(V_DISPATCH(disp) == (IDispatch*)wb, "V_DISPATCH(disp)=%p, wb=%p\n", V_DISPATCH(disp), wb); + + ok(V_VT(url) == (VT_BYREF|VT_VARIANT), "V_VT(url)=%x, expected VT_BYREF|VT_VARIANT\n", V_VT(url)); + ok(V_VARIANTREF(url) != NULL, "V_VARIANTREF(url) == NULL)\n"); + if(V_VARIANTREF(url)) { + ok(V_VT(V_VARIANTREF(url)) == VT_BSTR, "V_VT(V_VARIANTREF(url))=%d, expected VT_BSTR\n", + V_VT(V_VARIANTREF(url))); + ok(V_BSTR(V_VARIANTREF(url)) != NULL, "V_BSTR(V_VARIANTREF(url)) == NULL\n"); + ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), about_blankW), "unexpected url %s\n", + debugstr_w(V_BSTR(V_VARIANTREF(url)))); + } + + ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(flags)); + ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(flags)); + ok(V_VARIANTREF(flags) != NULL, "V_VARIANTREF(flags) == NULL)\n"); + if(V_VARIANTREF(flags)) { + ok(V_VT(V_VARIANTREF(flags)) == VT_I4, "V_VT(V_VARIANTREF(flags))=%d, expected VT_I4\n", + V_VT(V_VARIANTREF(flags))); + ok(V_I4(V_VARIANTREF(flags)) == 0, "V_I4(V_VARIANTREF(flags)) = %d, expected 0\n", + V_I4(V_VARIANTREF(flags))); + } + + ok(V_VT(frame) == (VT_BYREF|VT_VARIANT), "V_VT(frame)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(frame)); + ok(V_VT(frame) == (VT_BYREF|VT_VARIANT), "V_VT(frame)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(frame)); + ok(V_VARIANTREF(frame) != NULL, "V_VARIANTREF(frame) == NULL)\n"); + if(V_VARIANTREF(frame)) { + ok(V_VT(V_VARIANTREF(frame)) == VT_BSTR, "V_VT(V_VARIANTREF(frame))=%d, expected VT_BSTR\n", + V_VT(V_VARIANTREF(frame))); + ok(V_BSTR(V_VARIANTREF(frame)) == NULL, "V_BSTR(V_VARIANTREF(frame)) = %p, expected NULL\n", + V_BSTR(V_VARIANTREF(frame))); + } + + ok(V_VT(post_data) == (VT_BYREF|VT_VARIANT), "V_VT(post_data)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(post_data)); + ok(V_VT(post_data) == (VT_BYREF|VT_VARIANT), "V_VT(post_data)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(post_data)); + ok(V_VARIANTREF(post_data) != NULL, "V_VARIANTREF(post_data) == NULL)\n"); + if(V_VARIANTREF(post_data)) { + ok(V_VT(V_VARIANTREF(post_data)) == (VT_VARIANT|VT_BYREF), + "V_VT(V_VARIANTREF(post_data))=%d, expected VT_VARIANT|VT_BYREF\n", + V_VT(V_VARIANTREF(post_data))); + ok(V_VARIANTREF(V_VARIANTREF(post_data)) != NULL, + "V_VARIANTREF(V_VARIANTREF(post_data)) == NULL\n"); + if(V_VARIANTREF(V_VARIANTREF(post_data))) { + ok(V_VT(V_VARIANTREF(V_VARIANTREF(post_data))) == VT_EMPTY, + "V_VT(V_VARIANTREF(V_VARIANTREF(post_data))) = %d, expected VT_EMPTY\n", + V_VT(V_VARIANTREF(V_VARIANTREF(post_data)))); + + if(V_VT(V_VARIANTREF(V_VARIANTREF(post_data))) == (VT_UI1|VT_ARRAY)) { + const SAFEARRAY *sa = V_ARRAY(V_VARIANTREF(V_VARIANTREF(post_data))); + + ok(sa->cDims == 1, "sa->cDims = %d, expected 1\n", sa->cDims); + ok(sa->fFeatures == 0, "sa->fFeatures = %d, expected 0\n", sa->fFeatures); + } + } + } + + ok(V_VT(headers) == (VT_BYREF|VT_VARIANT), "V_VT(headers)=%x, expected VT_BYREF|VT_VARIANT\n", + V_VT(headers)); + ok(V_VARIANTREF(headers) != NULL, "V_VARIANTREF(headers) == NULL)\n"); + if(V_VARIANTREF(headers)) { + ok(V_VT(V_VARIANTREF(headers)) == VT_BSTR, "V_VT(V_VARIANTREF(headers))=%d, expected VT_BSTR\n", + V_VT(V_VARIANTREF(headers))); + ok(V_BSTR(V_VARIANTREF(headers)) == NULL, "V_BSTR(V_VARIANTREF(heders)) = %p, expected NULL\n", + V_BSTR(V_VARIANTREF(headers))); + } + + ok(V_VT(cancel) == (VT_BYREF|VT_BOOL), "V_VT(cancel)=%x, expected VT_BYREF|VT_BOOL\n", + V_VT(cancel)); + ok(V_BOOLREF(cancel) != NULL, "V_BOOLREF(pDispParams->rgvarg[0] == NULL)\n"); + if(V_BOOLREF(cancel)) + ok(*V_BOOLREF(cancel) == VARIANT_FALSE, "*V_BOOLREF(calcel) = %x, expected VARIANT_FALSE\n", + *V_BOOLREF(cancel)); +} + +static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(IsEqualGUID(&IID_NULL, riid), "riid != IID_NULL\n"); + ok(pDispParams != NULL, "pDispParams == NULL\n"); + ok(pExcepInfo == NULL, "pExcepInfo=%p, expected NULL\n", pExcepInfo); + ok(pVarResult == NULL, "pVarResult=%p\n", pVarResult); + ok(wFlags == DISPATCH_METHOD, "wFlags=%08x, expected DISPATCH_METHOD\n", wFlags); + ok(pDispParams->rgdispidNamedArgs == NULL, + "pDispParams->rgdispidNamedArgs = %p\n", pDispParams->rgdispidNamedArgs); + ok(pDispParams->cNamedArgs == 0, "pDispParams->cNamedArgs = %d\n", pDispParams->cNamedArgs); + + switch(dispIdMember) { + case DISPID_STATUSTEXTCHANGE: + CHECK_EXPECT2(Invoke_STATUSTEXTCHANGE); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 1, "cArgs=%d, expected 1\n", pDispParams->cArgs); + ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(pDispParams->rgvarg)=%d, expected VT_BSTR\n", + V_VT(pDispParams->rgvarg)); + /* TODO: Check text */ + break; + + case DISPID_PROPERTYCHANGE: + CHECK_EXPECT2(Invoke_PROPERTYCHANGE); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 1, "cArgs=%d, expected 1\n", pDispParams->cArgs); + /* TODO: Check args */ + break; + + case DISPID_DOWNLOADBEGIN: + CHECK_EXPECT(Invoke_DOWNLOADBEGIN); + + ok(pDispParams->rgvarg == NULL, "rgvarg=%p, expected NULL\n", pDispParams->rgvarg); + ok(pDispParams->cArgs == 0, "cArgs=%d, expected 0\n", pDispParams->cArgs); + break; + + case DISPID_BEFORENAVIGATE2: + CHECK_EXPECT(Invoke_BEFORENAVIGATE2); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 7, "cArgs=%d, expected 7\n", pDispParams->cArgs); + test_OnBeforeNavigate(pDispParams->rgvarg+6, pDispParams->rgvarg+5, pDispParams->rgvarg+4, + pDispParams->rgvarg+3, pDispParams->rgvarg+2, pDispParams->rgvarg+1, + pDispParams->rgvarg); + break; + + case DISPID_SETSECURELOCKICON: + CHECK_EXPECT2(Invoke_SETSECURELOCKICON); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 1, "cArgs=%d, expected 1\n", pDispParams->cArgs); + /* TODO: Check args */ + break; + + case DISPID_FILEDOWNLOAD: + CHECK_EXPECT(Invoke_FILEDOWNLOAD); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 2, "cArgs=%d, expected 2\n", pDispParams->cArgs); + /* TODO: Check args */ + break; + + case DISPID_COMMANDSTATECHANGE: + CHECK_EXPECT2(Invoke_COMMANDSTATECHANGE); + + ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n"); + ok(pDispParams->cArgs == 2, "cArgs=%d, expected 2\n", pDispParams->cArgs); + /* TODO: Check args */ + break; + + case DISPID_DOWNLOADCOMPLETE: + CHECK_EXPECT(Invoke_DOWNLOADCOMPLETE); + + ok(pDispParams->rgvarg == NULL, "rgvarg=%p, expected NULL\n", pDispParams->rgvarg); + ok(pDispParams->cArgs == 0, "cArgs=%d, expected 0\n", pDispParams->cArgs); + break; + + case DISPID_ONMENUBAR: + CHECK_EXPECT(Invoke_ONMENUBAR); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_ONADDRESSBAR: + CHECK_EXPECT(Invoke_ONADDRESSBAR); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_ONSTATUSBAR: + CHECK_EXPECT(Invoke_ONSTATUSBAR); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_ONTOOLBAR: + CHECK_EXPECT(Invoke_ONTOOLBAR); + test_invoke_bool(pDispParams, FALSE); + break; + + case DISPID_ONFULLSCREEN: + CHECK_EXPECT(Invoke_ONFULLSCREEN); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_ONTHEATERMODE: + CHECK_EXPECT(Invoke_ONTHEATERMODE); + test_invoke_bool(pDispParams, TRUE); + break; + + case DISPID_WINDOWSETRESIZABLE: + CHECK_EXPECT(Invoke_WINDOWSETRESIZABLE); + test_invoke_bool(pDispParams, TRUE); + break; + + default: + ok(0, "unexpected dispIdMember %d\n", dispIdMember); + } + + return S_OK; +} + +static IDispatchVtbl WebBrowserEvents2Vtbl = { + WebBrowserEvents2_QueryInterface, + Dispatch_AddRef, + Dispatch_Release, + Dispatch_GetTypeInfoCount, + Dispatch_GetTypeInfo, + Dispatch_GetIDsOfNames, + WebBrowserEvents2_Invoke +}; + +static IDispatch WebBrowserEvents2 = { &WebBrowserEvents2Vtbl }; + +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) +{ + CHECK_EXPECT(GetContainer); + + ok(ppContainer != NULL, "ppContainer == NULL\n"); + if(ppContainer) + *ppContainer = &OleContainer; + + return S_OK; +} + +static HRESULT WINAPI ClientSite_ShowObject(IOleClientSite *iface) +{ + CHECK_EXPECT(ShowObject); + return S_OK; +} + +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 InPlaceUIWindow_QueryInterface(IOleInPlaceFrame *iface, + REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI InPlaceUIWindow_AddRef(IOleInPlaceFrame *iface) +{ + return 2; +} + +static ULONG WINAPI InPlaceUIWindow_Release(IOleInPlaceFrame *iface) +{ + return 1; +} + +static HRESULT WINAPI InPlaceUIWindow_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_GetWindow(IOleInPlaceFrame *iface, HWND *phwnd) +{ + CHECK_EXPECT(Frame_GetWindow); + ok(phwnd != NULL, "phwnd == NULL\n"); + if(phwnd) + *phwnd = container_hwnd; + return S_OK; +} + +static HRESULT WINAPI InPlaceUIWindow_ContextSensitiveHelp(IOleInPlaceFrame *iface, BOOL fEnterMode) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceUIWindow_GetBorder(IOleInPlaceFrame *iface, LPRECT lprectBorder) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceUIWindow_RequestBorderSpace(IOleInPlaceFrame *iface, + LPCBORDERWIDTHS pborderwidths) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceUIWindow_SetBorderSpace(IOleInPlaceFrame *iface, + LPCBORDERWIDTHS pborderwidths) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceUIWindow_SetActiveObject(IOleInPlaceFrame *iface, + IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + CHECK_EXPECT(UIWindow_SetActiveObject); + ok(pActiveObject != NULL, "pActiveObject = NULL\n"); + ok(!lstrcmpW(pszObjName, wszItem), "unexpected pszObjName\n"); + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_SetActiveObject(IOleInPlaceFrame *iface, + IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName) +{ + CHECK_EXPECT(Frame_SetActiveObject); + ok(pActiveObject != NULL, "pActiveObject = NULL\n"); + ok(!lstrcmpW(pszObjName, wszItem), "unexpected pszObjName\n"); + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_InsertMenus(IOleInPlaceFrame *iface, HMENU hmenuShared, + LPOLEMENUGROUPWIDTHS lpMenuWidths) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceFrame_SetMenu(IOleInPlaceFrame *iface, HMENU hmenuShared, + HOLEMENU holemenu, HWND hwndActiveObject) +{ + CHECK_EXPECT(SetMenu); + ok(hmenuShared == NULL, "hmenuShared=%p\n", hmenuShared); + ok(holemenu == NULL, "holemenu=%p\n", holemenu); + ok(hwndActiveObject == shell_embedding_hwnd, "hwndActiveObject=%p, expected %p\n", + hwndActiveObject, shell_embedding_hwnd); + return S_OK; +} + +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) +{ + CHECK_EXPECT2(SetStatusText); + /* FIXME: Check pszStatusText */ + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_EnableModeless(IOleInPlaceFrame *iface, BOOL fEnable) +{ + if(fEnable) + CHECK_EXPECT(EnableModeless_TRUE); + else + CHECK_EXPECT(EnableModeless_FALSE); + return S_OK; +} + +static HRESULT WINAPI InPlaceFrame_TranslateAccelerator(IOleInPlaceFrame *iface, LPMSG lpmsg, WORD wID) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IOleInPlaceFrameVtbl InPlaceUIWindowVtbl = { + InPlaceUIWindow_QueryInterface, + InPlaceUIWindow_AddRef, + InPlaceUIWindow_Release, + InPlaceUIWindow_GetWindow, + InPlaceUIWindow_ContextSensitiveHelp, + InPlaceUIWindow_GetBorder, + InPlaceUIWindow_RequestBorderSpace, + InPlaceUIWindow_SetBorderSpace, + InPlaceUIWindow_SetActiveObject, +}; + +static IOleInPlaceUIWindow InPlaceUIWindow = { (IOleInPlaceUIWindowVtbl*)&InPlaceUIWindowVtbl }; + +static const IOleInPlaceFrameVtbl InPlaceFrameVtbl = { + InPlaceUIWindow_QueryInterface, + InPlaceUIWindow_AddRef, + InPlaceUIWindow_Release, + InPlaceFrame_GetWindow, + InPlaceUIWindow_ContextSensitiveHelp, + InPlaceUIWindow_GetBorder, + InPlaceUIWindow_RequestBorderSpace, + InPlaceUIWindow_SetBorderSpace, + InPlaceFrame_SetActiveObject, + InPlaceFrame_InsertMenus, + InPlaceFrame_SetMenu, + InPlaceFrame_RemoveMenus, + InPlaceFrame_SetStatusText, + InPlaceFrame_EnableModeless, + InPlaceFrame_TranslateAccelerator +}; + +static IOleInPlaceFrame InPlaceFrame = { &InPlaceFrameVtbl }; + +static HRESULT WINAPI InPlaceSite_QueryInterface(IOleInPlaceSiteEx *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI InPlaceSite_AddRef(IOleInPlaceSiteEx *iface) +{ + return 2; +} + +static ULONG WINAPI InPlaceSite_Release(IOleInPlaceSiteEx *iface) +{ + return 1; +} + +static HRESULT WINAPI InPlaceSite_GetWindow(IOleInPlaceSiteEx *iface, HWND *phwnd) +{ + CHECK_EXPECT(Site_GetWindow); + ok(phwnd != NULL, "phwnd == NULL\n"); + if(phwnd) + *phwnd = container_hwnd; + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_ContextSensitiveHelp(IOleInPlaceSiteEx *iface, BOOL fEnterMode) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_CanInPlaceActivate(IOleInPlaceSiteEx *iface) +{ + CHECK_EXPECT(CanInPlaceActivate); + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceActivate(IOleInPlaceSiteEx *iface) +{ + CHECK_EXPECT(OnInPlaceActivate); + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_OnUIActivate(IOleInPlaceSiteEx *iface) +{ + CHECK_EXPECT(OnUIActivate); + return S_OK; +} + +static HRESULT WINAPI InPlaceSite_GetWindowContext(IOleInPlaceSiteEx *iface, + IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, + LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) +{ + static const RECT pos_rect = {2,1,1002,901}; + static const RECT clip_rect = {10,10,990,890}; + + CHECK_EXPECT(GetWindowContext); + + ok(ppFrame != NULL, "ppFrame = NULL\n"); + if(ppFrame) + *ppFrame = &InPlaceFrame; + + ok(ppDoc != NULL, "ppDoc = NULL\n"); + if(ppDoc) + *ppDoc = &InPlaceUIWindow; + + ok(lprcPosRect != NULL, "lprcPosRect = NULL\n"); + if(lprcPosRect) + memcpy(lprcPosRect, &pos_rect, sizeof(RECT)); + + ok(lprcClipRect != NULL, "lprcClipRect = NULL\n"); + if(lprcClipRect) + memcpy(lprcClipRect, &clip_rect, sizeof(RECT)); + + ok(lpFrameInfo != NULL, "lpFrameInfo = NULL\n"); + if(lpFrameInfo) { + 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(IOleInPlaceSiteEx *iface, SIZE scrollExtant) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnUIDeactivate(IOleInPlaceSiteEx *iface, BOOL fUndoable) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceDeactivate(IOleInPlaceSiteEx *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_DiscardUndoState(IOleInPlaceSiteEx *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_DeactivateAndUndo(IOleInPlaceSiteEx *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnPosRectChange(IOleInPlaceSiteEx *iface, LPCRECT lprcPosRect) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceActivateEx(IOleInPlaceSiteEx *iface, + BOOL *pNoRedraw, DWORD dwFlags) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_OnInPlaceDeactivateEx(IOleInPlaceSiteEx *iface, + BOOL fNoRedraw) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI InPlaceSite_RequestUIActivate(IOleInPlaceSiteEx *iface) +{ + ok(0, "unexpected call\n"); + return S_OK; +} + +static const IOleInPlaceSiteExVtbl InPlaceSiteExVtbl = { + 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, + InPlaceSite_OnInPlaceActivateEx, + InPlaceSite_OnInPlaceDeactivateEx, + InPlaceSite_RequestUIActivate +}; + +static IOleInPlaceSiteEx InPlaceSite = { &InPlaceSiteExVtbl }; + +static HRESULT WINAPI DocHostUIHandler_QueryInterface(IDocHostUIHandler2 *iface, REFIID riid, void **ppv) +{ + return QueryInterface(riid, ppv); +} + +static ULONG WINAPI DocHostUIHandler_AddRef(IDocHostUIHandler2 *iface) +{ + return 2; +} + +static ULONG WINAPI DocHostUIHandler_Release(IDocHostUIHandler2 *iface) +{ + return 1; +} + +static HRESULT WINAPI DocHostUIHandler_ShowContextMenu(IDocHostUIHandler2 *iface, DWORD dwID, POINT *ppt, + IUnknown *pcmdtReserved, IDispatch *pdicpReserved) +{ + ok(0, "unexpected call %d %p %p %p\n", dwID, ppt, pcmdtReserved, pdicpReserved); + return S_FALSE; +} + +static HRESULT WINAPI DocHostUIHandler_GetHostInfo(IDocHostUIHandler2 *iface, DOCHOSTUIINFO *pInfo) +{ + CHECK_EXPECT2(GetHostInfo); + ok(pInfo != NULL, "pInfo=NULL\n"); + if(pInfo) { + ok(pInfo->cbSize == sizeof(DOCHOSTUIINFO) || broken(!pInfo->cbSize), "pInfo->cbSize=%u\n", pInfo->cbSize); + ok(!pInfo->dwFlags, "pInfo->dwFlags=%08x, expected 0\n", pInfo->dwFlags); + ok(!pInfo->dwDoubleClick, "pInfo->dwDoubleClick=%08x, expected 0\n", pInfo->dwDoubleClick); + ok(!pInfo->pchHostCss, "pInfo->pchHostCss=%p, expected NULL\n", pInfo->pchHostCss); + ok(!pInfo->pchHostNS, "pInfo->pchhostNS=%p, expected NULL\n", pInfo->pchHostNS); + } + return E_FAIL; +} + +static HRESULT WINAPI DocHostUIHandler_ShowUI(IDocHostUIHandler2 *iface, DWORD dwID, + IOleInPlaceActiveObject *pActiveObject, IOleCommandTarget *pCommandTarget, + IOleInPlaceFrame *pFrame, IOleInPlaceUIWindow *pDoc) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_HideUI(IDocHostUIHandler2 *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_UpdateUI(IDocHostUIHandler2 *iface) +{ + CHECK_EXPECT(UpdateUI); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_EnableModeless(IDocHostUIHandler2 *iface, BOOL fEnable) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_OnDocWindowActivate(IDocHostUIHandler2 *iface, BOOL fActivate) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_OnFrameWindowActivate(IDocHostUIHandler2 *iface, BOOL fActivate) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_ResizeBorder(IDocHostUIHandler2 *iface, LPCRECT prcBorder, + IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_TranslateAccelerator(IDocHostUIHandler2 *iface, LPMSG lpMsg, + const GUID *pguidCmdGroup, DWORD nCmdID) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_GetOptionKeyPath(IDocHostUIHandler2 *iface, + LPOLESTR *pchKey, DWORD dw) +{ + CHECK_EXPECT(GetOptionKeyPath); + ok(pchKey != NULL, "pchKey==NULL\n"); + if(pchKey) + ok(*pchKey == NULL, "*pchKey=%p\n", *pchKey); + ok(!dw, "dw=%x\n", dw); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_GetDropTarget(IDocHostUIHandler2 *iface, + IDropTarget *pDropTarget, IDropTarget **ppDropTarget) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_GetExternal(IDocHostUIHandler2 *iface, IDispatch **ppDispatch) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_TranslateUrl(IDocHostUIHandler2 *iface, DWORD dwTranslate, + OLECHAR *pchURLIn, OLECHAR **ppchURLOut) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_FilterDataObject(IDocHostUIHandler2 *iface, IDataObject *pDO, + IDataObject **ppPORet) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DocHostUIHandler_GetOverrideKeyPath(IDocHostUIHandler2 *iface, + LPOLESTR *pchKey, DWORD dw) +{ + CHECK_EXPECT(GetOverridesKeyPath); + ok(pchKey != NULL, "pchKey==NULL\n"); + if(pchKey) + ok(*pchKey == NULL, "*pchKey=%p\n", *pchKey); + ok(!dw, "dw=%x\n", dw); + return E_NOTIMPL; +} + +static const IDocHostUIHandler2Vtbl DocHostUIHandlerVtbl = { + DocHostUIHandler_QueryInterface, + DocHostUIHandler_AddRef, + DocHostUIHandler_Release, + DocHostUIHandler_ShowContextMenu, + DocHostUIHandler_GetHostInfo, + DocHostUIHandler_ShowUI, + DocHostUIHandler_HideUI, + DocHostUIHandler_UpdateUI, + DocHostUIHandler_EnableModeless, + DocHostUIHandler_OnDocWindowActivate, + DocHostUIHandler_OnFrameWindowActivate, + DocHostUIHandler_ResizeBorder, + DocHostUIHandler_TranslateAccelerator, + DocHostUIHandler_GetOptionKeyPath, + DocHostUIHandler_GetDropTarget, + DocHostUIHandler_GetExternal, + DocHostUIHandler_TranslateUrl, + DocHostUIHandler_FilterDataObject, + DocHostUIHandler_GetOverrideKeyPath +}; + +static IDocHostUIHandler2 DocHostUIHandler = { &DocHostUIHandlerVtbl }; + +static HRESULT QueryInterface(REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid) + || IsEqualGUID(&IID_IOleClientSite, riid)) + *ppv = &ClientSite; + else if(IsEqualGUID(&IID_IOleWindow, riid) + || IsEqualGUID(&IID_IOleInPlaceSite, riid) + || IsEqualGUID(&IID_IOleInPlaceSiteEx, riid)) + *ppv = &InPlaceSite; + else if(IsEqualGUID(&IID_IDocHostUIHandler, riid) + || IsEqualGUID(&IID_IDocHostUIHandler2, riid)) + *ppv = &DocHostUIHandler; + else if(IsEqualGUID(&IID_IDispatch, riid)) + *ppv = &Dispatch; + + if(*ppv) + return S_OK; + + return E_NOINTERFACE; +} + +static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +static HWND create_container_window(void) +{ + static const WCHAR wszWebBrowserContainer[] = + {'W','e','b','B','r','o','w','s','e','r','C','o','n','t','a','i','n','e','r',0}; + static WNDCLASSEXW wndclass = { + sizeof(WNDCLASSEXW), + 0, + wnd_proc, + 0, 0, NULL, NULL, NULL, NULL, NULL, + wszWebBrowserContainer, + NULL + }; + + RegisterClassExW(&wndclass); + return CreateWindowW(wszWebBrowserContainer, wszWebBrowserContainer, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, NULL, NULL, NULL, NULL); +} + +static void test_DoVerb(IUnknown *unk) +{ + IOleObject *oleobj; + RECT rect = {0,0,1000,1000}; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj); + ok(hres == S_OK, "QueryInterface(IID_OleObject) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + SET_EXPECT(CanInPlaceActivate); + SET_EXPECT(Site_GetWindow); + SET_EXPECT(OnInPlaceActivate); + SET_EXPECT(GetWindowContext); + SET_EXPECT(ShowObject); + SET_EXPECT(GetContainer); + SET_EXPECT(Frame_GetWindow); + SET_EXPECT(OnUIActivate); + SET_EXPECT(Frame_SetActiveObject); + SET_EXPECT(UIWindow_SetActiveObject); + SET_EXPECT(SetMenu); + + hres = IOleObject_DoVerb(oleobj, OLEIVERB_SHOW, NULL, &ClientSite, + 0, (HWND)0xdeadbeef, &rect); + ok(hres == S_OK, "DoVerb failed: %08x\n", hres); + + CHECK_CALLED(CanInPlaceActivate); + CHECK_CALLED(Site_GetWindow); + CHECK_CALLED(OnInPlaceActivate); + CHECK_CALLED(GetWindowContext); + CHECK_CALLED(ShowObject); + CHECK_CALLED(GetContainer); + CHECK_CALLED(Frame_GetWindow); + CHECK_CALLED(OnUIActivate); + CHECK_CALLED(Frame_SetActiveObject); + CHECK_CALLED(UIWindow_SetActiveObject); + CHECK_CALLED(SetMenu); + + hres = IOleObject_DoVerb(oleobj, OLEIVERB_SHOW, NULL, &ClientSite, + 0, (HWND)0xdeadbeef, &rect); + ok(hres == S_OK, "DoVerb failed: %08x\n", hres); + + IOleObject_Release(oleobj); +} + +static void test_GetMiscStatus(IOleObject *oleobj) +{ + DWORD st, i; + HRESULT hres; + + for(i=0; i<10; i++) { + st = 0xdeadbeef; + hres = IOleObject_GetMiscStatus(oleobj, i, &st); + ok(hres == S_OK, "GetMiscStatus failed: %08x\n", hres); + ok(st == (OLEMISC_SETCLIENTSITEFIRST|OLEMISC_ACTIVATEWHENVISIBLE|OLEMISC_INSIDEOUT + |OLEMISC_CANTLINKINSIDE|OLEMISC_RECOMPOSEONRESIZE), + "st=%08x, expected OLEMISC_SETCLIENTSITEFIRST|OLEMISC_ACTIVATEWHENVISIBLE|" + "OLEMISC_INSIDEOUT|OLEMISC_CANTLINKINSIDE|OLEMISC_RECOMPOSEONRESIZE)\n", st); + } +} + +static void test_SetHostNames(IOleObject *oleobj) +{ + HRESULT hres; + + static const WCHAR test_appW[] = {'t','e','s','t',' ','a','p','p',0}; + + hres = IOleObject_SetHostNames(oleobj, test_appW, (void*)0xdeadbeef); + ok(hres == S_OK, "SetHostNames failed: %08x\n", hres); +} + +static void test_ClientSite(IUnknown *unk, IOleClientSite *client) +{ + IOleObject *oleobj; + IOleInPlaceObject *inplace; + HWND hwnd; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj); + ok(hres == S_OK, "QueryInterface(IID_OleObject) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + test_GetMiscStatus(oleobj); + test_SetHostNames(oleobj); + + hres = IUnknown_QueryInterface(unk, &IID_IOleInPlaceObject, (void**)&inplace); + ok(hres == S_OK, "QueryInterface(IID_OleInPlaceObject) failed: %08x\n", hres); + if(FAILED(hres)) { + IOleObject_Release(oleobj); + return; + } + + hres = IOleInPlaceObject_GetWindow(inplace, &hwnd); + ok(hres == S_OK, "GetWindow failed: %08x\n", hres); + ok((hwnd == NULL) ^ (client == NULL), "unexpected hwnd %p\n", hwnd); + + if(client) { + SET_EXPECT(GetContainer); + SET_EXPECT(Site_GetWindow); + SET_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + SET_EXPECT(Invoke_AMBIENT_SILENT); + }else { + SET_EXPECT(Invoke_DOWNLOADCOMPLETE); + SET_EXPECT(Exec_SETDOWNLOADSTATE_0); + SET_EXPECT(Invoke_COMMANDSTATECHANGE); + } + + hres = IOleObject_SetClientSite(oleobj, client); + ok(hres == S_OK, "SetClientSite failed: %08x\n", hres); + + if(client) { + CHECK_CALLED(GetContainer); + CHECK_CALLED(Site_GetWindow); + CHECK_CALLED(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + CHECK_CALLED(Invoke_AMBIENT_SILENT); + }else { + todo_wine CHECK_CALLED(Invoke_DOWNLOADCOMPLETE); + todo_wine CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); + todo_wine CHECK_CALLED(Invoke_COMMANDSTATECHANGE); + } + + hres = IOleInPlaceObject_GetWindow(inplace, &hwnd); + ok(hres == S_OK, "GetWindow failed: %08x\n", hres); + ok((hwnd == NULL) == (client == NULL), "unexpected hwnd %p\n", hwnd); + + shell_embedding_hwnd = hwnd; + + test_SetHostNames(oleobj); + + IOleInPlaceObject_Release(inplace); + IOleObject_Release(oleobj); +} + +static void test_ClassInfo(IUnknown *unk) +{ + IProvideClassInfo2 *class_info; + GUID guid; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IProvideClassInfo2, (void**)&class_info); + ok(hres == S_OK, "QueryInterface(IID_IProvideClassInfo) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IProvideClassInfo2_GetGUID(class_info, GUIDKIND_DEFAULT_SOURCE_DISP_IID, &guid); + ok(hres == S_OK, "GetGUID failed: %08x\n", hres); + ok(IsEqualGUID(&DIID_DWebBrowserEvents2, &guid), "wrong guid\n"); + + hres = IProvideClassInfo2_GetGUID(class_info, 0, &guid); + ok(hres == E_FAIL, "GetGUID failed: %08x, expected E_FAIL\n", hres); + ok(IsEqualGUID(&IID_NULL, &guid), "wrong guid\n"); + + hres = IProvideClassInfo2_GetGUID(class_info, 2, &guid); + ok(hres == E_FAIL, "GetGUID failed: %08x, expected E_FAIL\n", hres); + ok(IsEqualGUID(&IID_NULL, &guid), "wrong guid\n"); + + hres = IProvideClassInfo2_GetGUID(class_info, GUIDKIND_DEFAULT_SOURCE_DISP_IID, NULL); + ok(hres == E_POINTER, "GetGUID failed: %08x, expected E_POINTER\n", hres); + + hres = IProvideClassInfo2_GetGUID(class_info, 0, NULL); + ok(hres == E_POINTER, "GetGUID failed: %08x, expected E_POINTER\n", hres); + + IProvideClassInfo2_Release(class_info); +} + +static void test_ie_funcs(IUnknown *unk) +{ + IWebBrowser2 *wb; + IDispatch *disp; + VARIANT_BOOL b; + int i; + long hwnd; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&wb); + ok(hres == S_OK, "Could not get IWebBrowser2 interface: %08x\n", hres); + if(FAILED(hres)) + return; + + /* HWND */ + + hwnd = 0xdeadbeef; + hres = IWebBrowser2_get_HWND(wb, &hwnd); + ok(hres == E_FAIL, "get_HWND failed: %08x, expected E_FAIL\n", hres); + ok(hwnd == 0, "unexpected hwnd %lx\n", hwnd); + + /* MenuBar */ + + hres = IWebBrowser2_get_MenuBar(wb, &b); + ok(hres == S_OK, "get_MenuBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONMENUBAR); + hres = IWebBrowser2_put_MenuBar(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_MenuBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONMENUBAR); + + hres = IWebBrowser2_get_MenuBar(wb, &b); + ok(hres == S_OK, "get_MenuBar failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONMENUBAR); + hres = IWebBrowser2_put_MenuBar(wb, (exvb = 100)); + ok(hres == S_OK, "put_MenuBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONMENUBAR); + + hres = IWebBrowser2_get_MenuBar(wb, &b); + ok(hres == S_OK, "get_MenuBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + /* AddressBar */ + + hres = IWebBrowser2_get_AddressBar(wb, &b); + ok(hres == S_OK, "get_AddressBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONADDRESSBAR); + hres = IWebBrowser2_put_AddressBar(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_AddressBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONADDRESSBAR); + + hres = IWebBrowser2_get_AddressBar(wb, &b); + ok(hres == S_OK, "get_MenuBar failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONADDRESSBAR); + hres = IWebBrowser2_put_AddressBar(wb, (exvb = 100)); + ok(hres == S_OK, "put_AddressBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONADDRESSBAR); + + hres = IWebBrowser2_get_AddressBar(wb, &b); + ok(hres == S_OK, "get_AddressBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONADDRESSBAR); + hres = IWebBrowser2_put_AddressBar(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_MenuBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONADDRESSBAR); + + /* StatusBar */ + + hres = IWebBrowser2_get_StatusBar(wb, &b); + ok(hres == S_OK, "get_StatusBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONSTATUSBAR); + hres = IWebBrowser2_put_StatusBar(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_StatusBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONSTATUSBAR); + + hres = IWebBrowser2_get_StatusBar(wb, &b); + ok(hres == S_OK, "get_StatusBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONSTATUSBAR); + hres = IWebBrowser2_put_StatusBar(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_StatusBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONSTATUSBAR); + + hres = IWebBrowser2_get_StatusBar(wb, &b); + ok(hres == S_OK, "get_StatusBar failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONSTATUSBAR); + hres = IWebBrowser2_put_StatusBar(wb, (exvb = 100)); + ok(hres == S_OK, "put_StatusBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONSTATUSBAR); + + hres = IWebBrowser2_get_StatusBar(wb, &b); + ok(hres == S_OK, "get_StatusBar failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + /* ToolBar */ + + hres = IWebBrowser2_get_ToolBar(wb, &i); + ok(hres == S_OK, "get_ToolBar failed: %08x\n", hres); + ok(i, "i=%x\n", i); + + SET_EXPECT(Invoke_ONTOOLBAR); + hres = IWebBrowser2_put_ToolBar(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_ToolBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTOOLBAR); + + hres = IWebBrowser2_get_ToolBar(wb, &i); + ok(hres == S_OK, "get_ToolBar failed: %08x\n", hres); + ok(i == VARIANT_FALSE, "b=%x\n", i); + + SET_EXPECT(Invoke_ONTOOLBAR); + hres = IWebBrowser2_put_ToolBar(wb, (exvb = 100)); + ok(hres == S_OK, "put_ToolBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTOOLBAR); + + hres = IWebBrowser2_get_ToolBar(wb, &i); + ok(hres == S_OK, "get_ToolBar failed: %08x\n", hres); + ok(i, "i=%x\n", i); + + SET_EXPECT(Invoke_ONTOOLBAR); + hres = IWebBrowser2_put_ToolBar(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_ToolBar failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTOOLBAR); + + /* FullScreen */ + + hres = IWebBrowser2_get_FullScreen(wb, &b); + ok(hres == S_OK, "get_FullScreen failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONFULLSCREEN); + hres = IWebBrowser2_put_FullScreen(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_FullScreen failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONFULLSCREEN); + + hres = IWebBrowser2_get_FullScreen(wb, &b); + ok(hres == S_OK, "get_FullScreen failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONFULLSCREEN); + hres = IWebBrowser2_put_FullScreen(wb, (exvb = 100)); + ok(hres == S_OK, "put_FullScreen failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONFULLSCREEN); + + hres = IWebBrowser2_get_FullScreen(wb, &b); + ok(hres == S_OK, "get_FullScreen failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONFULLSCREEN); + hres = IWebBrowser2_put_FullScreen(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_FullScreen failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONFULLSCREEN); + + /* TheaterMode */ + + hres = IWebBrowser2_get_TheaterMode(wb, &b); + ok(hres == S_OK, "get_TheaterMode failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONTHEATERMODE); + hres = IWebBrowser2_put_TheaterMode(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK, "put_TheaterMode failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTHEATERMODE); + + hres = IWebBrowser2_get_TheaterMode(wb, &b); + ok(hres == S_OK, "get_TheaterMode failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONTHEATERMODE); + hres = IWebBrowser2_put_TheaterMode(wb, (exvb = 100)); + ok(hres == S_OK, "put_TheaterMode failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTHEATERMODE); + + hres = IWebBrowser2_get_TheaterMode(wb, &b); + ok(hres == S_OK, "get_TheaterMode failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + SET_EXPECT(Invoke_ONTHEATERMODE); + hres = IWebBrowser2_put_TheaterMode(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK, "put_TheaterMode failed: %08x\n", hres); + CHECK_CALLED(Invoke_ONTHEATERMODE); + + /* Resizable */ + + b = 0x100; + hres = IWebBrowser2_get_Resizable(wb, &b); + ok(hres == E_NOTIMPL, "get_Resizable failed: %08x\n", hres); + ok(b == 0x100, "b=%x\n", b); + + SET_EXPECT(Invoke_WINDOWSETRESIZABLE); + hres = IWebBrowser2_put_Resizable(wb, (exvb = VARIANT_TRUE)); + ok(hres == S_OK || broken(hres == E_NOTIMPL), "put_Resizable failed: %08x\n", hres); + CHECK_CALLED_BROKEN(Invoke_WINDOWSETRESIZABLE); + + SET_EXPECT(Invoke_WINDOWSETRESIZABLE); + hres = IWebBrowser2_put_Resizable(wb, (exvb = VARIANT_FALSE)); + ok(hres == S_OK || broken(hres == E_NOTIMPL), "put_Resizable failed: %08x\n", hres); + CHECK_CALLED_BROKEN(Invoke_WINDOWSETRESIZABLE); + + hres = IWebBrowser2_get_Resizable(wb, &b); + ok(hres == E_NOTIMPL, "get_Resizable failed: %08x\n", hres); + ok(b == 0x100, "b=%x\n", b); + + /* Application */ + + disp = NULL; + hres = IWebBrowser2_get_Application(wb, &disp); + ok(hres == S_OK, "get_Application failed: %08x\n", hres); + ok(disp == (void*)wb, "disp=%p, expected %p\n", disp, wb); + if(disp) + IDispatch_Release(disp); + + hres = IWebBrowser2_get_Application(wb, NULL); + ok(hres == E_POINTER, "get_Application failed: %08x, expected E_POINTER\n", hres); + + /* Quit */ + + hres = IWebBrowser2_Quit(wb); + ok(hres == E_FAIL, "Quit failed: %08x, expected E_FAIL\n", hres); + + IWebBrowser2_Release(wb); +} + +static void test_Silent(IWebBrowser2 *wb, IOleControl *control, BOOL is_clientsite) +{ + VARIANT_BOOL b; + HRESULT hres; + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + hres = IWebBrowser2_put_Silent(wb, VARIANT_TRUE); + ok(hres == S_OK, "set_Silent failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + hres = IWebBrowser2_put_Silent(wb, 100); + ok(hres == S_OK, "set_Silent failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + hres = IWebBrowser2_put_Silent(wb, VARIANT_FALSE); + ok(hres == S_OK, "set_Silent failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + if(is_clientsite) { + hres = IWebBrowser2_put_Silent(wb, VARIANT_TRUE); + ok(hres == S_OK, "set_Silent failed: %08x\n", hres); + + SET_EXPECT(Invoke_AMBIENT_SILENT); + } + + hres = IOleControl_OnAmbientPropertyChange(control, DISPID_AMBIENT_SILENT); + ok(hres == S_OK, "OnAmbientPropertyChange failed %08x\n", hres); + + if(is_clientsite) + CHECK_CALLED(Invoke_AMBIENT_SILENT); + + b = 100; + hres = IWebBrowser2_get_Silent(wb, &b); + ok(hres == S_OK, "get_Silent failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); +} + +static void test_Offline(IWebBrowser2 *wb, IOleControl *control, BOOL is_clientsite) +{ + VARIANT_BOOL b; + HRESULT hres; + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + hres = IWebBrowser2_put_Offline(wb, VARIANT_TRUE); + ok(hres == S_OK, "set_Offline failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + hres = IWebBrowser2_put_Offline(wb, 100); + ok(hres == S_OK, "set_Offline failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_TRUE, "b=%x\n", b); + + hres = IWebBrowser2_put_Offline(wb, VARIANT_FALSE); + ok(hres == S_OK, "set_Offline failed: %08x\n", hres); + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); + + if(is_clientsite) { + hres = IWebBrowser2_put_Offline(wb, VARIANT_TRUE); + ok(hres == S_OK, "set_Offline failed: %08x\n", hres); + + SET_EXPECT(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + } + + hres = IOleControl_OnAmbientPropertyChange(control, DISPID_AMBIENT_OFFLINEIFNOTCONNECTED); + ok(hres == S_OK, "OnAmbientPropertyChange failed %08x\n", hres); + + if(is_clientsite) + CHECK_CALLED(Invoke_AMBIENT_OFFLINEIFNOTCONNECTED); + + b = 100; + hres = IWebBrowser2_get_Offline(wb, &b); + ok(hres == S_OK, "get_Offline failed: %08x\n", hres); + ok(b == VARIANT_FALSE, "b=%x\n", b); +} + +static void test_wb_funcs(IUnknown *unk, BOOL is_clientsite) +{ + IWebBrowser2 *wb; + IOleControl *control; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&wb); + ok(hres == S_OK, "Could not get IWebBrowser2 interface: %08x\n", hres); + + hres = IUnknown_QueryInterface(unk, &IID_IOleControl, (void**)&control); + ok(hres == S_OK, "Could not get IOleControl interface: %08x\n", hres); + + test_Silent(wb, control, is_clientsite); + test_Offline(wb, control, is_clientsite); + + IWebBrowser_Release(wb); + IOleControl_Release(control); +} + +static void test_GetControlInfo(IUnknown *unk) +{ + IOleControl *control; + CONTROLINFO info; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IOleControl, (void**)&control); + ok(hres == S_OK, "Could not get IOleControl: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IOleControl_GetControlInfo(control, &info); + ok(hres == E_NOTIMPL, "GetControlInfo failed: %08x, exxpected E_NOTIMPL\n", hres); + hres = IOleControl_GetControlInfo(control, NULL); + ok(hres == E_NOTIMPL, "GetControlInfo failed: %08x, exxpected E_NOTIMPL\n", hres); + + IOleControl_Release(control); +} + +static void test_Extent(IUnknown *unk) +{ + IOleObject *oleobj; + SIZE size, expected; + HRESULT hres; + DWORD dpi_x; + DWORD dpi_y; + HDC hdc; + + /* default aspect ratio is 96dpi / 96dpi */ + hdc = GetDC(0); + dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); + dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(0, hdc); + if (dpi_x != 96 || dpi_y != 96) + trace("dpi: %d / %d\n", dpi_y, dpi_y); + + hres = IUnknown_QueryInterface(unk, &IID_IOleObject, (void**)&oleobj); + ok(hres == S_OK, "Could not get IOleObkect: %08x\n", hres); + if(FAILED(hres)) + return; + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, DVASPECT_CONTENT, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + /* Default size is 50x20 pixels, in himetric units */ + expected.cx = MulDiv( 50, 2540, dpi_x ); + expected.cy = MulDiv( 20, 2540, dpi_y ); + ok(size.cx == expected.cx && size.cy == expected.cy, "size = {%d %d} (expected %d %d)\n", + size.cx, size.cy, expected.cx, expected.cy ); + + size.cx = 800; + size.cy = 700; + hres = IOleObject_SetExtent(oleobj, DVASPECT_CONTENT, &size); + ok(hres == S_OK, "SetExtent failed: %08x\n", hres); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, DVASPECT_CONTENT, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 800 && size.cy == 700, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, 0, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 800 && size.cy == 700, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = 900; + size.cy = 800; + hres = IOleObject_SetExtent(oleobj, 0, &size); + ok(hres == S_OK, "SetExtent failed: %08x\n", hres); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, 0, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 900 && size.cy == 800, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, 0xdeadbeef, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 900 && size.cy == 800, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = 1000; + size.cy = 900; + hres = IOleObject_SetExtent(oleobj, 0xdeadbeef, &size); + ok(hres == S_OK, "SetExtent failed: %08x\n", hres); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, 0xdeadbeef, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 1000 && size.cy == 900, "size = {%d %d}\n", size.cx, size.cy); + + size.cx = size.cy = 0xdeadbeef; + hres = IOleObject_GetExtent(oleobj, DVASPECT_CONTENT, &size); + ok(hres == S_OK, "GetExtent failed: %08x\n", hres); + ok(size.cx == 1000 && size.cy == 900, "size = {%d %d}\n", size.cx, size.cy); + + IOleObject_Release(oleobj); +} + +static void test_ConnectionPoint(IUnknown *unk, BOOL init) +{ + IConnectionPointContainer *container; + IConnectionPoint *point; + HRESULT hres; + + static DWORD dw = 100; + + hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container); + ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IConnectionPointContainer_FindConnectionPoint(container, &DIID_DWebBrowserEvents2, &point); + IConnectionPointContainer_Release(container); + ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres); + if(FAILED(hres)) + return; + + if(init) { + hres = IConnectionPoint_Advise(point, (IUnknown*)&WebBrowserEvents2, &dw); + ok(hres == S_OK, "Advise failed: %08x\n", hres); + ok(dw == 1, "dw=%d, expected 1\n", dw); + }else { + hres = IConnectionPoint_Unadvise(point, dw); + ok(hres == S_OK, "Unadvise failed: %08x\n", hres); + } + + IConnectionPoint_Release(point); +} + +static void test_Navigate2(IUnknown *unk) +{ + IWebBrowser2 *webbrowser; + VARIANT url; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&webbrowser); + ok(hres == S_OK, "QueryInterface(IID_IWebBrowser) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + test_LocationURL(unk, emptyW); + + V_VT(&url) = VT_BSTR; + V_BSTR(&url) = SysAllocString(about_blankW); + + SET_EXPECT(Invoke_AMBIENT_USERMODE); + SET_EXPECT(Invoke_PROPERTYCHANGE); + SET_EXPECT(Invoke_BEFORENAVIGATE2); + SET_EXPECT(Invoke_DOWNLOADBEGIN); + SET_EXPECT(Exec_SETDOWNLOADSTATE_1); + SET_EXPECT(EnableModeless_FALSE); + SET_EXPECT(Invoke_STATUSTEXTCHANGE); + SET_EXPECT(SetStatusText); + SET_EXPECT(GetHostInfo); + SET_EXPECT(Invoke_AMBIENT_DLCONTROL); + SET_EXPECT(Invoke_AMBIENT_USERAGENT); + SET_EXPECT(Invoke_AMBIENT_PALETTE); + SET_EXPECT(GetOptionKeyPath); + SET_EXPECT(GetOverridesKeyPath); + SET_EXPECT(QueryStatus_SETPROGRESSTEXT); + SET_EXPECT(Exec_SETPROGRESSMAX); + SET_EXPECT(Exec_SETPROGRESSPOS); + SET_EXPECT(Invoke_SETSECURELOCKICON); + SET_EXPECT(Invoke_FILEDOWNLOAD); + SET_EXPECT(Exec_SETDOWNLOADSTATE_0); + SET_EXPECT(Invoke_COMMANDSTATECHANGE); + SET_EXPECT(EnableModeless_TRUE); + + hres = IWebBrowser2_Navigate2(webbrowser, &url, NULL, NULL, NULL, NULL); + ok(hres == S_OK, "Navigate2 failed: %08x\n", hres); + + CHECK_CALLED(Invoke_AMBIENT_USERMODE); + todo_wine CHECK_CALLED(Invoke_PROPERTYCHANGE); + CHECK_CALLED(Invoke_BEFORENAVIGATE2); + todo_wine CHECK_CALLED(Invoke_DOWNLOADBEGIN); + todo_wine CHECK_CALLED(Exec_SETDOWNLOADSTATE_1); + CHECK_CALLED(EnableModeless_FALSE); + CHECK_CALLED(Invoke_STATUSTEXTCHANGE); + CHECK_CALLED(SetStatusText); + CHECK_CALLED(GetHostInfo); + CHECK_CALLED(Invoke_AMBIENT_DLCONTROL); + CHECK_CALLED(Invoke_AMBIENT_USERAGENT); + CHECK_CALLED(Invoke_AMBIENT_PALETTE); + CHECK_CALLED(GetOptionKeyPath); + CHECK_CALLED_BROKEN(GetOverridesKeyPath); + todo_wine CHECK_CALLED(QueryStatus_SETPROGRESSTEXT); + todo_wine CHECK_CALLED(Exec_SETPROGRESSMAX); + todo_wine CHECK_CALLED(Exec_SETPROGRESSPOS); + todo_wine CHECK_CALLED_BROKEN(Invoke_SETSECURELOCKICON); + todo_wine CHECK_CALLED_BROKEN(Invoke_FILEDOWNLOAD); + todo_wine CHECK_CALLED(Invoke_COMMANDSTATECHANGE); + todo_wine CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); + CHECK_CALLED(EnableModeless_TRUE); + + VariantClear(&url); + IWebBrowser2_Release(webbrowser); +} + +static void test_IServiceProvider(IUnknown *unk) +{ + IServiceProvider *servprov = (void*)0xdeadbeef; + HRESULT hres; + IUnknown *ret = NULL; + static const IID IID_IBrowserService2 = + {0x68BD21CC,0x438B,0x11d2,{0xA5,0x60,0x00,0xA0,0xC,0x2D,0xBF,0xE8}}; + + hres = IUnknown_QueryInterface(unk, &IID_IServiceProvider, (void**)&servprov); + ok(hres == S_OK, "QueryInterface returned %08x, expected S_OK\n", hres); + if(FAILED(hres)) + return; + + hres = IServiceProvider_QueryService(servprov, &SID_STopLevelBrowser, &IID_IBrowserService2, (LPVOID*)&ret); + ok(hres == E_FAIL, "QueryService returned %08x, expected E_FAIL\n", hres); + ok(ret == NULL, "ret returned %p, expected NULL\n", ret); + if(hres == S_OK) + { + IUnknown_Release(ret); + } + + IServiceProvider_Release(servprov); +} + +static void test_QueryInterface(IUnknown *unk) +{ + IQuickActivate *qa = (IQuickActivate*)0xdeadbeef; + IRunnableObject *runnable = (IRunnableObject*)0xdeadbeef; + IPerPropertyBrowsing *propbrowse = (void*)0xdeadbeef; + IOleInPlaceSite *inplace = (void*)0xdeadbeef; + IOleCache *cache = (void*)0xdeadbeef; + IObjectWithSite *site = (void*)0xdeadbeef; + IViewObjectEx *viewex = (void*)0xdeadbeef; + HRESULT hres; + + hres = IUnknown_QueryInterface(unk, &IID_IQuickActivate, (void**)&qa); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(qa == NULL, "qa=%p, expected NULL\n", qa); + + hres = IUnknown_QueryInterface(unk, &IID_IRunnableObject, (void**)&runnable); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(runnable == NULL, "runnable=%p, expected NULL\n", runnable); + + hres = IUnknown_QueryInterface(unk, &IID_IPerPropertyBrowsing, (void**)&propbrowse); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(propbrowse == NULL, "propbrowse=%p, expected NULL\n", propbrowse); + + hres = IUnknown_QueryInterface(unk, &IID_IOleCache, (void**)&cache); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(cache == NULL, "cache=%p, expected NULL\n", cache); + + hres = IUnknown_QueryInterface(unk, &IID_IOleInPlaceSite, (void**)&inplace); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(inplace == NULL, "inplace=%p, expected NULL\n", inplace); + + hres = IUnknown_QueryInterface(unk, &IID_IObjectWithSite, (void**)&site); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(site == NULL, "site=%p, expected NULL\n", site); + + hres = IUnknown_QueryInterface(unk, &IID_IViewObjectEx, (void**)&viewex); + ok(hres == E_NOINTERFACE, "QueryInterface returned %08x, expected E_NOINTERFACE\n", hres); + ok(viewex == NULL, "viewex=%p, expected NULL\n", viewex); + +} + +static void test_WebBrowser(void) +{ + IUnknown *unk = NULL; + ULONG ref; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_WebBrowser, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IUnknown, (void**)&unk); + ok(hres == S_OK, "CoCreateInterface failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IUnknown_QueryInterface(unk, &IID_IWebBrowser2, (void**)&wb); + ok(hres == S_OK, "Could not get IWebBrowser2 iface: %08x\n", hres); + + test_QueryInterface(unk); + test_ClassInfo(unk); + test_LocationURL(unk, emptyW); + test_ConnectionPoint(unk, TRUE); + test_ClientSite(unk, &ClientSite); + test_Extent(unk); + test_wb_funcs(unk, TRUE); + test_DoVerb(unk); + test_Navigate2(unk); + test_ClientSite(unk, NULL); + test_ie_funcs(unk); + test_GetControlInfo(unk); + test_wb_funcs(unk, FALSE); + test_ConnectionPoint(unk, FALSE); + test_IServiceProvider(unk); + + IWebBrowser2_Release(wb); + ref = IUnknown_Release(unk); + ok(ref == 0, "ref=%d, expected 0\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); +} + +START_TEST(webbrowser) +{ + gecko_installer_workaround(TRUE); + + container_hwnd = create_container_window(); + + OleInitialize(NULL); + + test_WebBrowser(); + + OleUninitialize(); + + gecko_installer_workaround(FALSE); +}