HRESULT __RPC_STUB ITypeInfo_GetDocumentation_Stub( ITypeInfo* This, MEMBERID memid, DWORD refPtrFlags, BSTR* pBstrName, BSTR* pBstrDocString, DWORD* pdwHelpContext, BSTR* pBstrHelpFile) { TRACE("(%p, %08lx, %08lx, %p, %p, %p, %p)\n", This, memid, refPtrFlags, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); return ITypeInfo_GetDocumentation(This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); }
static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti) { func_info_t *info; HRESULT hres; if(data->func_cnt && data->funcs[data->func_cnt-1].id == desc->memid) { info = data->funcs+data->func_cnt-1; }else { if(data->func_cnt == *size) data->funcs = heap_realloc(data->funcs, (*size <<= 1)*sizeof(func_info_t)); info = data->funcs+data->func_cnt; hres = ITypeInfo_GetDocumentation(dti, desc->memid, &info->name, NULL, NULL, NULL); if(FAILED(hres)) return; data->func_cnt++; info->id = desc->memid; info->tid = tid; info->func_disp_idx = -1; info->prop_vt = VT_EMPTY; info->put_vtbl_off = 0; info->get_vtbl_off = 0; } if(desc->invkind & DISPATCH_METHOD) { info->func_disp_idx = data->func_disp_cnt++; }else if(desc->invkind & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYGET)) { VARTYPE vt = VT_EMPTY; if(desc->invkind & DISPATCH_PROPERTYGET) { vt = desc->elemdescFunc.tdesc.vt; info->get_vtbl_off = desc->oVft/sizeof(void*); } if(desc->invkind & DISPATCH_PROPERTYPUT) { assert(desc->cParams == 1); vt = desc->lprgelemdescParam->tdesc.vt; info->put_vtbl_off = desc->oVft/sizeof(void*); } assert(info->prop_vt == VT_EMPTY || vt == info->prop_vt); info->prop_vt = vt; } }
static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, DISPID id, ITypeInfo *dti) { HRESULT hres; if(data->func_cnt && data->funcs[data->func_cnt-1].id == id) return; if(data->func_cnt == *size) data->funcs = heap_realloc(data->funcs, (*size <<= 1)*sizeof(func_info_t)); hres = ITypeInfo_GetDocumentation(dti, id, &data->funcs[data->func_cnt].name, NULL, NULL, NULL); if(FAILED(hres)) return; data->funcs[data->func_cnt].id = id; data->funcs[data->func_cnt].tid = tid; data->func_cnt++; }
static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti) { HRESULT hres; if(data->func_cnt && data->funcs[data->func_cnt-1].id == desc->memid) return; if(data->func_cnt == *size) data->funcs = heap_realloc(data->funcs, (*size <<= 1)*sizeof(func_info_t)); hres = ITypeInfo_GetDocumentation(dti, desc->memid, &data->funcs[data->func_cnt].name, NULL, NULL, NULL); if(FAILED(hres)) return; data->funcs[data->func_cnt].id = desc->memid; data->funcs[data->func_cnt].tid = tid; data->funcs[data->func_cnt].func_disp_idx = (desc->invkind & DISPATCH_METHOD) ? data->func_disp_cnt++ : -1; data->func_cnt++; }
static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti) { func_info_t *info; HRESULT hres; for(info = data->funcs; info < data->funcs+data->func_cnt; info++) { if(info->id == desc->memid) { if(info->tid != tid) return; /* Duplicated in other interface */ break; } } if(info == data->funcs+data->func_cnt) { if(data->func_cnt == *size) data->funcs = heap_realloc_zero(data->funcs, (*size <<= 1)*sizeof(func_info_t)); info = data->funcs+data->func_cnt; hres = ITypeInfo_GetDocumentation(dti, desc->memid, &info->name, NULL, NULL, NULL); if(FAILED(hres)) return; data->func_cnt++; info->id = desc->memid; info->tid = tid; info->func_disp_idx = -1; info->prop_vt = VT_EMPTY; } if(desc->invkind & DISPATCH_METHOD) { unsigned i; info->func_disp_idx = data->func_disp_cnt++; info->argc = desc->cParams; assert(info->argc < MAX_ARGS); assert(desc->funckind == FUNC_DISPATCH); info->arg_types = heap_alloc(sizeof(*info->arg_types) * info->argc); if(!info->arg_types) return; /* FIXME: real error instead of fallback */ for(i=0; i < info->argc; i++) info->arg_types[i] = desc->lprgelemdescParam[i].tdesc.vt; info->prop_vt = desc->elemdescFunc.tdesc.vt; if(info->prop_vt != VT_VOID && !is_arg_type_supported(info->prop_vt)) { TRACE("%s: return type %d\n", debugstr_w(info->name), info->prop_vt); return; /* Fallback to ITypeInfo::Invoke */ } if(desc->cParamsOpt) { TRACE("%s: optional params\n", debugstr_w(info->name)); return; /* Fallback to ITypeInfo::Invoke */ } for(i=0; i < info->argc; i++) { if(!is_arg_type_supported(info->arg_types[i])) { return; /* Fallback to ITypeInfo for unsupported arg types */ } if(desc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) { TRACE("%s param %d: default value\n", debugstr_w(info->name), i); return; /* Fallback to ITypeInfo::Invoke */ } } assert(info->argc <= MAX_ARGS); assert(desc->callconv == CC_STDCALL); info->call_vtbl_off = desc->oVft/sizeof(void*); }else if(desc->invkind & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYGET)) { VARTYPE vt = VT_EMPTY; if(desc->invkind & DISPATCH_PROPERTYGET) { vt = desc->elemdescFunc.tdesc.vt; info->get_vtbl_off = desc->oVft/sizeof(void*); } if(desc->invkind & DISPATCH_PROPERTYPUT) { assert(desc->cParams == 1); vt = desc->lprgelemdescParam->tdesc.vt; info->put_vtbl_off = desc->oVft/sizeof(void*); } assert(info->prop_vt == VT_EMPTY || vt == info->prop_vt); info->prop_vt = vt; } }
/****************************************************************************** * GetRecordInfoFromTypeInfo [OLEAUT32.332] */ HRESULT WINAPI GetRecordInfoFromTypeInfo(ITypeInfo* pTI, IRecordInfo** ppRecInfo) { HRESULT hres; TYPEATTR *typeattr; IRecordInfoImpl *ret; ITypeInfo *pTypeInfo; int i; GUID guid; TRACE("(%p %p)\n", pTI, ppRecInfo); if(!pTI || !ppRecInfo) return E_INVALIDARG; hres = ITypeInfo_GetTypeAttr(pTI, &typeattr); if(FAILED(hres) || !typeattr) { WARN("GetTypeAttr failed: %08x\n", hres); return hres; } if(typeattr->typekind == TKIND_ALIAS) { hres = ITypeInfo_GetRefTypeInfo(pTI, typeattr->tdescAlias.u.hreftype, &pTypeInfo); guid = typeattr->guid; ITypeInfo_ReleaseTypeAttr(pTI, typeattr); if(FAILED(hres)) { WARN("GetRefTypeInfo failed: %08x\n", hres); return hres; } ITypeInfo_GetTypeAttr(pTypeInfo, &typeattr); }else { pTypeInfo = pTI; ITypeInfo_AddRef(pTypeInfo); guid = typeattr->guid; } if(typeattr->typekind != TKIND_RECORD) { WARN("typekind != TKIND_RECORD\n"); ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr); ITypeInfo_Release(pTypeInfo); return E_INVALIDARG; } ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret)); ret->IRecordInfo_iface.lpVtbl = &IRecordInfoImplVtbl; ret->ref = 1; ret->pTypeInfo = pTypeInfo; ret->n_vars = typeattr->cVars; ret->size = typeattr->cbSizeInstance; ITypeInfo_ReleaseTypeAttr(pTypeInfo, typeattr); ret->guid = guid; /* NOTE: Windows implementation calls ITypeInfo::GetCantainingTypeLib and * ITypeLib::GetLibAttr, but we currently don't need this. */ hres = ITypeInfo_GetDocumentation(pTypeInfo, MEMBERID_NIL, &ret->name, NULL, NULL, NULL); if(FAILED(hres)) { WARN("ITypeInfo::GetDocumentation failed\n"); ret->name = NULL; } ret->fields = HeapAlloc(GetProcessHeap(), 0, ret->n_vars*sizeof(fieldstr)); for(i = 0; i<ret->n_vars; i++) { VARDESC *vardesc; hres = ITypeInfo_GetVarDesc(pTypeInfo, i, &vardesc); if(FAILED(hres)) { WARN("GetVarDesc failed\n"); continue; } ret->fields[i].vt = vardesc->elemdescVar.tdesc.vt; ret->fields[i].varkind = vardesc->varkind; ret->fields[i].offset = vardesc->u.oInst; hres = ITypeInfo_GetDocumentation(pTypeInfo, vardesc->memid, &ret->fields[i].name, NULL, NULL, NULL); if(FAILED(hres)) WARN("GetDocumentation failed: %08x\n", hres); ITypeInfo_ReleaseVarDesc(pTypeInfo, vardesc); } *ppRecInfo = &ret->IRecordInfo_iface; return S_OK; }
int php_com_process_typeinfo(ITypeInfo *typeinfo, HashTable *id_to_name, int printdef, GUID *guid, int codepage) { TYPEATTR *attr; FUNCDESC *func; int i; OLECHAR *olename; char *ansiname = NULL; size_t ansinamelen; int ret = 0; if (FAILED(ITypeInfo_GetTypeAttr(typeinfo, &attr))) { return 0; } /* verify that it is suitable */ if (id_to_name == NULL || attr->typekind == TKIND_DISPATCH) { if (guid) { memcpy(guid, &attr->guid, sizeof(GUID)); } if (printdef) { char *guidstring; ITypeInfo_GetDocumentation(typeinfo, MEMBERID_NIL, &olename, NULL, NULL, NULL); ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage); SysFreeString(olename); guidstring = php_com_string_from_clsid(&attr->guid, codepage); php_printf("class %s { /* GUID=%s */\n", ansiname, guidstring); efree(guidstring); efree(ansiname); } if (id_to_name) { zend_hash_init(id_to_name, 0, NULL, ZVAL_PTR_DTOR, 0); } /* So we've got the dispatch interface; lets list the event methods */ for (i = 0; i < attr->cFuncs; i++) { zval tmp; DISPID lastid = 0; /* for props */ int isprop; if (FAILED(ITypeInfo_GetFuncDesc(typeinfo, i, &func))) break; isprop = (func->invkind & DISPATCH_PROPERTYGET || func->invkind & DISPATCH_PROPERTYPUT); if (!isprop || lastid != func->memid) { lastid = func->memid; ITypeInfo_GetDocumentation(typeinfo, func->memid, &olename, NULL, NULL, NULL); ansiname = php_com_olestring_to_string(olename, &ansinamelen, codepage); SysFreeString(olename); if (printdef) { int j; char *funcdesc; size_t funcdesclen; unsigned int cnames = 0; BSTR *names; names = (BSTR*)safe_emalloc((func->cParams + 1), sizeof(BSTR), 0); ITypeInfo_GetNames(typeinfo, func->memid, names, func->cParams + 1, &cnames); /* first element is the function name */ SysFreeString(names[0]); php_printf("\t/* DISPID=%d */\n", func->memid); if (func->elemdescFunc.tdesc.vt != VT_VOID) { php_printf("\t/* %s [%d] */\n", vt_to_string(func->elemdescFunc.tdesc.vt), func->elemdescFunc.tdesc.vt ); } if (isprop) { ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL); if (olename) { funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage); SysFreeString(olename); php_printf("\t/* %s */\n", funcdesc); efree(funcdesc); } php_printf("\tvar $%s;\n\n", ansiname); } else { /* a function */ php_printf("\tfunction %s(\n", ansiname); for (j = 0; j < func->cParams; j++) { ELEMDESC *elem = &func->lprgelemdescParam[j]; php_printf("\t\t/* %s [%d] ", vt_to_string(elem->tdesc.vt), elem->tdesc.vt); if (elem->paramdesc.wParamFlags & PARAMFLAG_FIN) php_printf("[in]"); if (elem->paramdesc.wParamFlags & PARAMFLAG_FOUT) php_printf("[out]"); if (elem->tdesc.vt == VT_PTR) { /* what does it point to ? */ php_printf(" --> %s [%d] ", vt_to_string(elem->tdesc.lptdesc->vt), elem->tdesc.lptdesc->vt ); } /* when we handle prop put and get, this will look nicer */ if (j+1 < (int)cnames) { funcdesc = php_com_olestring_to_string(names[j+1], &funcdesclen, codepage); SysFreeString(names[j+1]); } else { funcdesc = "???"; } php_printf(" */ %s%s%c\n", elem->tdesc.vt == VT_PTR ? "&$" : "$", funcdesc, j == func->cParams - 1 ? ' ' : ',' ); if (j+1 < (int)cnames) { efree(funcdesc); } } php_printf("\t\t)\n\t{\n"); ITypeInfo_GetDocumentation(typeinfo, func->memid, NULL, &olename, NULL, NULL); if (olename) { funcdesc = php_com_olestring_to_string(olename, &funcdesclen, codepage); SysFreeString(olename); php_printf("\t\t/* %s */\n", funcdesc); efree(funcdesc); } php_printf("\t}\n"); } efree(names); } if (id_to_name) { zend_str_tolower(ansiname, ansinamelen); ZVAL_STRINGL(&tmp, ansiname, ansinamelen); zend_hash_index_update(id_to_name, func->memid, &tmp); // TODO: avoid reallocation??? efree(ansiname); } } ITypeInfo_ReleaseFuncDesc(typeinfo, func); } if (printdef) { php_printf("}\n"); } ret = 1; } else { zend_error(E_WARNING, "That's not a dispatchable interface!! type kind = %08x", attr->typekind); } ITypeInfo_ReleaseTypeAttr(typeinfo, attr); return ret; }
static void test_xmlelem(void) { HRESULT hr; IXMLDocument *doc = NULL; IXMLElement *element = NULL, *parent; IXMLElement *child, *child2; IXMLElementCollection *children; VARIANT vType, vName; VARIANT vIndex, vValue; BSTR str, val, name; LONG type, num_child; IDispatch *disp; ITypeInfo *ti; static const WCHAR propName[] = {'p','r','o','p',0}; static const WCHAR propVal[] = {'v','a','l',0}; static const WCHAR nextVal[] = {'n','e','x','t',0}; static const WCHAR noexist[] = {'n','o','e','x','i','s','t',0}; static const WCHAR crazyCase1[] = {'C','R','a','z','Y','c','A','S','E',0}; static const WCHAR crazyCase2[] = {'C','R','A','Z','Y','C','A','S','E',0}; hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDocument, (LPVOID*)&doc); EXPECT_HR(hr, S_OK); V_VT(&vType) = VT_I4; V_I4(&vType) = XMLELEMTYPE_ELEMENT; V_VT(&vName) = VT_NULL; hr = IXMLDocument_createElement(doc, vType, vName, &element); EXPECT_HR(hr, S_OK); ok(element != NULL, "Expected non-NULL element\n"); /* test for IDispatch */ disp = NULL; hr = IXMLElement_QueryInterface(element, &IID_IDispatch, (void**)&disp); EXPECT_HR(hr, S_OK); hr = IDispatch_GetTypeInfo(disp, 0, 0, &ti); EXPECT_HR(hr, S_OK); name = NULL; hr = ITypeInfo_GetDocumentation(ti, DISPID_XMLELEMENT_TAGNAME, &name, NULL, NULL, NULL); EXPECT_HR(hr, S_OK); SysFreeString(name); ITypeInfo_Release(ti); IDispatch_Release(disp); hr = IXMLElement_get_tagName(element, &str); EXPECT_HR(hr, S_OK); ok(!str, "Expected empty tag name, got %s\n", wine_dbgstr_w(str)); SysFreeString(str); parent = (IXMLElement *)0xdeadbeef; hr = IXMLElement_get_parent(element, &parent); ok(hr == 1, "Expected 1, got %08x\n", hr); ok(parent == NULL, "Expected NULL parent\n"); str = SysAllocString(noexist); hr = IXMLElement_getAttribute(element, str, &vValue); ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); ok(V_VT(&vValue) == VT_EMPTY, "Expected VT_EMPTY, got %d\n", V_VT(&vValue)); ok(V_BSTR(&vValue) == NULL, "Expected null value\n"); VariantClear(&vValue); SysFreeString(str); str = SysAllocString(crazyCase1); val = SysAllocString(propVal); V_VT(&vValue) = VT_BSTR; V_BSTR(&vValue) = val; hr = IXMLElement_setAttribute(element, str, vValue); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); SysFreeString(str); SysFreeString(val); str = SysAllocString(crazyCase2); hr = IXMLElement_getAttribute(element, str, &vValue); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(V_VT(&vValue) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&vValue)); ok(!lstrcmpW(V_BSTR(&vValue), propVal), "Expected 'val'\n"); VariantClear(&vValue); SysFreeString(str); str = SysAllocString(propName); val = SysAllocString(propVal); V_VT(&vValue) = VT_BSTR; V_BSTR(&vValue) = val; hr = IXMLElement_setAttribute(element, str, vValue); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); SysFreeString(val); hr = IXMLElement_getAttribute(element, str, &vValue); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(V_VT(&vValue) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&vValue)); ok(!lstrcmpW(V_BSTR(&vValue), propVal), "Expected 'val'\n"); VariantClear(&vValue); hr = IXMLElement_removeAttribute(element, str); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); /* remove now nonexistent attribute */ hr = IXMLElement_removeAttribute(element, str); ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr); hr = IXMLElement_getAttribute(element, str, &vValue); ok(hr == 1, "Expected 1, got %08x\n", hr); ok(V_VT(&vValue) == VT_EMPTY, "Expected VT_EMPTY, got %d\n", V_VT(&vValue)); ok(V_BSTR(&vValue) == NULL, "Expected null value\n"); SysFreeString(str); VariantClear(&vValue); children = (IXMLElementCollection *)0xdeadbeef; hr = IXMLElement_get_children(element, &children); ok(hr == 1, "Expected 1, got %08x\n", hr); ok(children == NULL, "Expected NULL collection\n"); hr = IXMLElement_get_type(element, &type); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); hr = IXMLElement_get_text(element, &str); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(lstrlenW(str) == 0, "Expected empty text\n"); SysFreeString(str); /* put_text with an ELEMENT */ str = SysAllocString(propVal); hr = IXMLElement_put_text(element, str); ok(hr == E_NOTIMPL, "Expected E_NOTIMPL, got %08x\n", hr); SysFreeString(str); V_VT(&vType) = VT_I4; V_I4(&vType) = XMLELEMTYPE_TEXT; V_VT(&vName) = VT_NULL; hr = IXMLDocument_createElement(doc, vType, vName, &child); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(child != NULL, "Expected non-NULL child\n"); hr = IXMLElement_addChild(element, child, 0, -1); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); str = SysAllocString(propVal); hr = IXMLElement_put_text(child, str); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); SysFreeString(str); parent = (IXMLElement *)0xdeadbeef; hr = IXMLElement_get_parent(child, &parent); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(parent != element, "Expected parent != element\n"); hr = IXMLElement_get_type(parent, &type); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); children = (IXMLElementCollection *)0xdeadbeef; hr = IXMLElement_get_children(element, &children); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(children != NULL, "Expected non-NULL collection\n"); hr = IXMLElementCollection_get_length(children, &num_child); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(num_child == 1, "Expected 1, got %d\n", num_child); V_VT(&vIndex) = VT_I4; V_I4(&vIndex) = 0; V_VT(&vName) = VT_ERROR; V_ERROR(&vName) = DISP_E_PARAMNOTFOUND; hr = IXMLElementCollection_item(children, vIndex, vName, (IDispatch **)&child2); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(child2 != NULL, "Expected non-NULL child\n"); hr = IXMLElement_get_type(child2, &type); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(type == XMLELEMTYPE_TEXT, "Expected XMLELEMTYPE_TEXT, got %d\n", type); hr = IXMLElement_get_text(element, &str); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(str, propVal), "Expected 'val'\n"); SysFreeString(str); hr = IXMLElement_get_text(child2, &str); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(str, propVal), "Expected 'val'\n"); SysFreeString(str); /* try put_text on ELEMENT again, now that it has a text child */ str = SysAllocString(nextVal); hr = IXMLElement_put_text(element, str); ok(hr == E_NOTIMPL, "Expected E_NOTIMPL, got %08x\n", hr); SysFreeString(str); str = SysAllocString(nextVal); hr = IXMLElement_put_text(child2, str); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); SysFreeString(str); hr = IXMLElement_get_text(element, &str); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(str, nextVal), "Expected 'val'\n"); SysFreeString(str); IXMLElement_Release(child2); IXMLElementCollection_Release(children); IXMLElement_Release(parent); IXMLElement_Release(child); IXMLElement_Release(element); IXMLDocument_Release(doc); }
static void test_xmldoc(void) { IXMLElement *element = NULL, *child = NULL, *value = NULL; IXMLElementCollection *collection = NULL, *inner = NULL; IPersistStreamInit *psi = NULL; IXMLDocument *doc = NULL; IStream *stream = NULL; VARIANT vIndex, vName; LONG type, num_child; CHAR path[MAX_PATH]; IDispatch *disp; ITypeInfo *ti; HRESULT hr; BSTR name; static const WCHAR szBankAccount[] = {'B','A','N','K','A','C','C','O','U','N','T',0}; static const WCHAR szNumber[] = {'N','U','M','B','E','R',0}; static const WCHAR szNumVal[] = {'1','2','3','4',0}; static const WCHAR szName[] = {'N','A','M','E',0}; static const WCHAR szNameVal[] = {'C','a','p','t','a','i','n',' ','A','h','a','b',0}; static const WCHAR szVersion[] = {'1','.','0',0}; static const WCHAR rootW[] = {'r','o','o','t',0}; hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDocument, (void**)&doc); EXPECT_HR(hr, S_OK); /* IDispatch */ hr = IXMLDocument_QueryInterface(doc, &IID_IDispatch, (void**)&disp); EXPECT_HR(hr, S_OK); /* just to make sure we're on right type data */ hr = IDispatch_GetTypeInfo(disp, 0, 0, &ti); EXPECT_HR(hr, S_OK); name = NULL; hr = ITypeInfo_GetDocumentation(ti, DISPID_XMLDOCUMENT_ROOT, &name, NULL, NULL, NULL); EXPECT_HR(hr, S_OK); ok(!lstrcmpW(name, rootW), "got name %s\n", wine_dbgstr_w(name)); SysFreeString(name); ITypeInfo_Release(ti); IDispatch_Release(disp); hr = IXMLDocument_QueryInterface(doc, &IID_IXMLDOMDocument, (void**)&disp); EXPECT_HR(hr, E_NOINTERFACE); create_xml_file("bank.xml"); GetFullPathNameA("bank.xml", MAX_PATH, path, NULL); create_stream_on_file(&stream, path); hr = IXMLDocument_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&psi); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(psi != NULL, "Expected non-NULL psi\n"); hr = IXMLDocument_get_root(doc, &element); ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr); ok(element == NULL, "Expected NULL element\n"); hr = IPersistStreamInit_Load(psi, stream); ok(hr == S_OK || hr == XML_E_INVALIDATROOTLEVEL, "Expected S_OK, got %08x\n", hr); if(hr == XML_E_INVALIDATROOTLEVEL) goto cleanup; ok(stream != NULL, "Expected non-NULL stream\n"); /* version field */ hr = IXMLDocument_get_version(doc, NULL); ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); name = NULL; hr = IXMLDocument_get_version(doc, &name); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(name, szVersion), "Expected 1.0, got %s\n", wine_dbgstr_w(name)); SysFreeString(name); /* doctype */ hr = IXMLDocument_get_doctype(doc, NULL); ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr); hr = IXMLDocument_get_doctype(doc, &name); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(name, szBankAccount), "Expected BANKACCOUNT, got %s\n", wine_dbgstr_w(name)); SysFreeString(name); hr = IXMLDocument_get_root(doc, &element); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(element != NULL, "Expected non-NULL element\n"); /* ::root() returns new instance each time */ hr = IXMLDocument_get_root(doc, &child); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(child != NULL, "Expected non-NULL element\n"); ok(child != element, "Expected new element instance\n"); IXMLElement_Release(child); hr = IXMLElement_get_type(element, &type); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); hr = IXMLElement_get_tagName(element, &name); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(name, szBankAccount), "Expected BANKACCOUNT\n"); SysFreeString(name); hr = IXMLElement_get_children(element, &collection); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(collection != NULL, "Expected non-NULL collection\n"); hr = IXMLElementCollection_get_length(collection, &num_child); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(num_child == 2, "Expected 2, got %d\n", num_child); V_VT(&vIndex) = VT_I4; V_I4(&vIndex) = 0; V_VT(&vName) = VT_ERROR; V_ERROR(&vName) = DISP_E_PARAMNOTFOUND; hr = IXMLElementCollection_item(collection, vIndex, vName, (IDispatch **)&child); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(child != NULL, "Expected non-NULL child\n"); hr = IXMLElement_get_type(child, &type); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); hr = IXMLElement_get_tagName(child, &name); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(name, szNumber), "Expected NUMBER\n"); SysFreeString(name); hr = IXMLElement_get_children(child, &inner); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(inner != NULL, "Expected non-NULL inner\n"); hr = IXMLElementCollection_get_length(inner, &num_child); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(num_child == 1, "Expected 1, got %d\n", num_child); hr = IXMLElementCollection_item(inner, vIndex, vName, (IDispatch **)&value); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(value != NULL, "Expected non-NULL value\n"); hr = IXMLElement_get_type(value, &type); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(type == XMLELEMTYPE_TEXT, "Expected XMLELEMTYPE_TEXT, got %d\n", type); hr = IXMLElement_get_text(value, &name); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(name, szNumVal), "Expected '1234'\n"); SysFreeString(name); IXMLElementCollection_Release(inner); inner = (IXMLElementCollection *)0xdeadbeef; hr = IXMLElement_get_children(value, &inner); ok(hr == 1, "Expected 1, got %08x\n", hr); ok(inner == NULL, "Expected NULL inner, got %p\n", inner); IXMLElement_Release(value); IXMLElement_Release(child); value = NULL; child = NULL; V_I4(&vIndex) = 1; hr = IXMLElementCollection_item(collection, vIndex, vName, (IDispatch **)&child); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(child != NULL, "Expected non-NULL child\n"); hr = IXMLElement_get_type(child, &type); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(type == XMLELEMTYPE_ELEMENT, "Expected XMLELEMTYPE_ELEMENT, got %d\n", type); hr = IXMLElement_get_tagName(child, &name); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(name, szName), "Expected NAME\n"); SysFreeString(name); hr = IXMLElement_get_children(child, &inner); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(inner != NULL, "Expected non-NULL inner\n"); hr = IXMLElementCollection_get_length(inner, &num_child); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(num_child == 1, "Expected 1, got %d\n", num_child); V_I4(&vIndex) = 0; hr = IXMLElementCollection_item(inner, vIndex, vName, (IDispatch **)&value); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(value != NULL, "Expected non-NULL value\n"); hr = IXMLElement_get_type(value, &type); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(type == XMLELEMTYPE_TEXT, "Expected XMLELEMTYPE_TEXT, got %d\n", type); hr = IXMLElement_get_text(value, &name); ok(hr == S_OK, "Expected S_OK, got %08x\n", hr); ok(!lstrcmpW(name, szNameVal), "Expected 'Captain Ahab'\n"); SysFreeString(name); IXMLElementCollection_Release(inner); inner = (IXMLElementCollection *)0xdeadbeef; hr = IXMLElement_get_children(value, &inner); ok(hr == 1, "Expected 1, got %08x\n", hr); ok(inner == NULL, "Expected NULL inner, got %p\n", inner); IXMLElement_Release(value); IXMLElement_Release(child); IXMLElementCollection_Release(collection); IXMLElement_Release(element); cleanup: IStream_Release(stream); IPersistStreamInit_Release(psi); IXMLDocument_Release(doc); DeleteFileA("bank.xml"); }