xref: /reactos/dll/win32/mshtml/htmlattr.c (revision 8a978a17)
1 /*
2  * Copyright 2011 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "mshtml_private.h"
20 
21 static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface)
22 {
23     return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute_iface);
24 }
25 
26 static HRESULT WINAPI HTMLDOMAttribute_QueryInterface(IHTMLDOMAttribute *iface,
27                                                  REFIID riid, void **ppv)
28 {
29     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
30 
31     TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
32 
33     if(IsEqualGUID(&IID_IUnknown, riid)) {
34         *ppv = &This->IHTMLDOMAttribute_iface;
35     }else if(IsEqualGUID(&IID_IHTMLDOMAttribute, riid)) {
36         *ppv = &This->IHTMLDOMAttribute_iface;
37     }else if(IsEqualGUID(&IID_IHTMLDOMAttribute2, riid)) {
38         *ppv = &This->IHTMLDOMAttribute2_iface;
39     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
40         return *ppv ? S_OK : E_NOINTERFACE;
41     }else {
42         WARN("%s not supported\n", debugstr_mshtml_guid(riid));
43         *ppv =  NULL;
44         return E_NOINTERFACE;
45     }
46 
47     IUnknown_AddRef((IUnknown*)*ppv);
48     return S_OK;
49 }
50 
51 static ULONG WINAPI HTMLDOMAttribute_AddRef(IHTMLDOMAttribute *iface)
52 {
53     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
54     LONG ref = InterlockedIncrement(&This->ref);
55 
56     TRACE("(%p) ref=%d\n", This, ref);
57 
58     return ref;
59 }
60 
61 static ULONG WINAPI HTMLDOMAttribute_Release(IHTMLDOMAttribute *iface)
62 {
63     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
64     LONG ref = InterlockedDecrement(&This->ref);
65 
66     TRACE("(%p) ref=%d\n", This, ref);
67 
68     if(!ref) {
69         assert(!This->elem);
70         release_dispex(&This->dispex);
71         heap_free(This->name);
72         heap_free(This);
73     }
74 
75     return ref;
76 }
77 
78 static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfoCount(IHTMLDOMAttribute *iface, UINT *pctinfo)
79 {
80     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
81     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
82 }
83 
84 static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfo(IHTMLDOMAttribute *iface, UINT iTInfo,
85                                               LCID lcid, ITypeInfo **ppTInfo)
86 {
87     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
88     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
89 }
90 
91 static HRESULT WINAPI HTMLDOMAttribute_GetIDsOfNames(IHTMLDOMAttribute *iface, REFIID riid,
92                                                 LPOLESTR *rgszNames, UINT cNames,
93                                                 LCID lcid, DISPID *rgDispId)
94 {
95     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
96     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
97             lcid, rgDispId);
98 }
99 
100 static HRESULT WINAPI HTMLDOMAttribute_Invoke(IHTMLDOMAttribute *iface, DISPID dispIdMember,
101                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
102                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
103 {
104     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
105     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
106             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
107 }
108 
109 static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BSTR *p)
110 {
111     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
112 
113     TRACE("(%p)->(%p)\n", This, p);
114 
115     if(!This->elem) {
116         if(!This->name) {
117             FIXME("No name available\n");
118             return E_FAIL;
119         }
120 
121         *p = SysAllocString(This->name);
122         return *p ? S_OK : E_OUTOFMEMORY;
123     }
124 
125     return IDispatchEx_GetMemberName(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, p);
126 }
127 
128 static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, VARIANT v)
129 {
130     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
131     DISPID dispidNamed = DISPID_PROPERTYPUT;
132     DISPPARAMS dp = {&v, &dispidNamed, 1, 1};
133     EXCEPINFO ei;
134     VARIANT ret;
135 
136     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
137 
138     if(!This->elem) {
139         FIXME("NULL This->elem\n");
140         return E_UNEXPECTED;
141     }
142 
143     memset(&ei, 0, sizeof(ei));
144 
145     return IDispatchEx_InvokeEx(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, LOCALE_SYSTEM_DEFAULT,
146             DISPATCH_PROPERTYPUT, &dp, &ret, &ei, NULL);
147 }
148 
149 static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, VARIANT *p)
150 {
151     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
152 
153     TRACE("(%p)->(%p)\n", This, p);
154 
155     if(!This->elem) {
156         FIXME("NULL This->elem\n");
157         return E_UNEXPECTED;
158     }
159 
160     return get_elem_attr_value_by_dispid(This->elem, This->dispid, 0, p);
161 }
162 
163 static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, VARIANT_BOOL *p)
164 {
165     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
166     nsIDOMAttr *nsattr;
167     nsAString nsname;
168     BSTR name;
169     nsresult nsres;
170     HRESULT hres;
171 
172     TRACE("(%p)->(%p)\n", This, p);
173 
174     if(!This->elem || !This->elem->nselem) {
175         FIXME("NULL This->elem\n");
176         return E_UNEXPECTED;
177     }
178 
179     if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) {
180         *p = VARIANT_TRUE;
181         return S_OK;
182     }
183 
184     hres = IDispatchEx_GetMemberName(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, &name);
185     if(FAILED(hres))
186         return hres;
187 
188     /* FIXME: This is not exactly right, we have some attributes that don't map directly to Gecko attributes. */
189     nsAString_InitDepend(&nsname, name);
190     nsres = nsIDOMHTMLElement_GetAttributeNode(This->elem->nselem, &nsname, &nsattr);
191     nsAString_Finish(&nsname);
192     SysFreeString(name);
193     if(NS_FAILED(nsres))
194         return E_FAIL;
195 
196     /* If the Gecko attribute node can be found, we know that the attribute is specified.
197        There is no point in calling GetSpecified */
198     if(nsattr) {
199         nsIDOMAttr_Release(nsattr);
200         *p = VARIANT_TRUE;
201     }else {
202         *p = VARIANT_FALSE;
203     }
204     return S_OK;
205 }
206 
207 static const IHTMLDOMAttributeVtbl HTMLDOMAttributeVtbl = {
208     HTMLDOMAttribute_QueryInterface,
209     HTMLDOMAttribute_AddRef,
210     HTMLDOMAttribute_Release,
211     HTMLDOMAttribute_GetTypeInfoCount,
212     HTMLDOMAttribute_GetTypeInfo,
213     HTMLDOMAttribute_GetIDsOfNames,
214     HTMLDOMAttribute_Invoke,
215     HTMLDOMAttribute_get_nodeName,
216     HTMLDOMAttribute_put_nodeValue,
217     HTMLDOMAttribute_get_nodeValue,
218     HTMLDOMAttribute_get_specified
219 };
220 
221 static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute2(IHTMLDOMAttribute2 *iface)
222 {
223     return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute2_iface);
224 }
225 
226 static HRESULT WINAPI HTMLDOMAttribute2_QueryInterface(IHTMLDOMAttribute2 *iface, REFIID riid, void **ppv)
227 {
228     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
229     return IHTMLDOMAttribute_QueryInterface(&This->IHTMLDOMAttribute_iface, riid, ppv);
230 }
231 
232 static ULONG WINAPI HTMLDOMAttribute2_AddRef(IHTMLDOMAttribute2 *iface)
233 {
234     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
235     return IHTMLDOMAttribute_AddRef(&This->IHTMLDOMAttribute_iface);
236 }
237 
238 static ULONG WINAPI HTMLDOMAttribute2_Release(IHTMLDOMAttribute2 *iface)
239 {
240     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
241     return IHTMLDOMAttribute_Release(&This->IHTMLDOMAttribute_iface);
242 }
243 
244 static HRESULT WINAPI HTMLDOMAttribute2_GetTypeInfoCount(IHTMLDOMAttribute2 *iface, UINT *pctinfo)
245 {
246     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
247     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
248 }
249 
250 static HRESULT WINAPI HTMLDOMAttribute2_GetTypeInfo(IHTMLDOMAttribute2 *iface, UINT iTInfo,
251         LCID lcid, ITypeInfo **ppTInfo)
252 {
253     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
254     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
255 }
256 
257 static HRESULT WINAPI HTMLDOMAttribute2_GetIDsOfNames(IHTMLDOMAttribute2 *iface, REFIID riid,
258         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
259 {
260     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
261     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
262             lcid, rgDispId);
263 }
264 
265 static HRESULT WINAPI HTMLDOMAttribute2_Invoke(IHTMLDOMAttribute2 *iface, DISPID dispIdMember,
266         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
267         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
268 {
269     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
270     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
271             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
272 }
273 
274 static HRESULT WINAPI HTMLDOMAttribute2_get_name(IHTMLDOMAttribute2 *iface, BSTR *p)
275 {
276     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
277     FIXME("(%p)->(%p)\n", This, p);
278     return E_NOTIMPL;
279 }
280 
281 static HRESULT WINAPI HTMLDOMAttribute2_put_value(IHTMLDOMAttribute2 *iface, BSTR v)
282 {
283     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
284     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
285     return E_NOTIMPL;
286 }
287 
288 static HRESULT WINAPI HTMLDOMAttribute2_get_value(IHTMLDOMAttribute2 *iface, BSTR *p)
289 {
290     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
291     VARIANT val;
292     HRESULT hres;
293 
294     TRACE("(%p)->(%p)\n", This, p);
295 
296     if(!This->elem) {
297         FIXME("NULL This->elem\n");
298         return E_UNEXPECTED;
299     }
300 
301     hres = get_elem_attr_value_by_dispid(This->elem, This->dispid, ATTRFLAG_ASSTRING, &val);
302     if(FAILED(hres))
303         return hres;
304 
305     assert(V_VT(&val) == VT_BSTR);
306     *p = V_BSTR(&val);
307     if(!*p && !(*p = SysAllocStringLen(NULL, 0)))
308         return E_OUTOFMEMORY;
309     return S_OK;
310 }
311 
312 static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, VARIANT_BOOL *p)
313 {
314     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
315 
316     TRACE("(%p)->(%p)\n", This, p);
317 
318     *p = get_dispid_type(This->dispid) == DISPEXPROP_BUILTIN ? VARIANT_FALSE : VARIANT_TRUE;
319     return S_OK;
320 }
321 
322 static HRESULT WINAPI HTMLDOMAttribute2_get_nodeType(IHTMLDOMAttribute2 *iface, LONG *p)
323 {
324     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
325     FIXME("(%p)->(%p)\n", This, p);
326     return E_NOTIMPL;
327 }
328 
329 static HRESULT WINAPI HTMLDOMAttribute2_get_parentNode(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
330 {
331     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
332     FIXME("(%p)->(%p)\n", This, p);
333     return E_NOTIMPL;
334 }
335 
336 static HRESULT WINAPI HTMLDOMAttribute2_get_childNodes(IHTMLDOMAttribute2 *iface, IDispatch **p)
337 {
338     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
339     FIXME("(%p)->(%p)\n", This, p);
340     return E_NOTIMPL;
341 }
342 
343 static HRESULT WINAPI HTMLDOMAttribute2_get_firstChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
344 {
345     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
346     FIXME("(%p)->(%p)\n", This, p);
347     return E_NOTIMPL;
348 }
349 
350 static HRESULT WINAPI HTMLDOMAttribute2_get_lastChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
351 {
352     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
353     FIXME("(%p)->(%p)\n", This, p);
354     return E_NOTIMPL;
355 }
356 
357 static HRESULT WINAPI HTMLDOMAttribute2_get_previousSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
358 {
359     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
360     FIXME("(%p)->(%p)\n", This, p);
361     return E_NOTIMPL;
362 }
363 
364 static HRESULT WINAPI HTMLDOMAttribute2_get_nextSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
365 {
366     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
367     FIXME("(%p)->(%p)\n", This, p);
368     return E_NOTIMPL;
369 }
370 
371 static HRESULT WINAPI HTMLDOMAttribute2_get_attributes(IHTMLDOMAttribute2 *iface, IDispatch **p)
372 {
373     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
374     FIXME("(%p)->(%p)\n", This, p);
375     return E_NOTIMPL;
376 }
377 
378 static HRESULT WINAPI HTMLDOMAttribute2_get_ownerDocument(IHTMLDOMAttribute2 *iface, IDispatch **p)
379 {
380     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
381     FIXME("(%p)->(%p)\n", This, p);
382     return E_NOTIMPL;
383 }
384 
385 static HRESULT WINAPI HTMLDOMAttribute2_insertBefore(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
386         VARIANT refChild, IHTMLDOMNode **node)
387 {
388     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
389     FIXME("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), node);
390     return E_NOTIMPL;
391 }
392 
393 static HRESULT WINAPI HTMLDOMAttribute2_replaceChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
394         IHTMLDOMNode *oldChild, IHTMLDOMNode **node)
395 {
396     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
397     FIXME("(%p)->(%p %p %p)\n", This, newChild, oldChild, node);
398     return E_NOTIMPL;
399 }
400 
401 static HRESULT WINAPI HTMLDOMAttribute2_removeChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *oldChild,
402         IHTMLDOMNode **node)
403 {
404     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
405     FIXME("(%p)->(%p %p)\n", This, oldChild, node);
406     return E_NOTIMPL;
407 }
408 
409 static HRESULT WINAPI HTMLDOMAttribute2_appendChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
410         IHTMLDOMNode **node)
411 {
412     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
413     FIXME("(%p)->(%p %p)\n", This, newChild, node);
414     return E_NOTIMPL;
415 }
416 
417 static HRESULT WINAPI HTMLDOMAttribute2_hasChildNodes(IHTMLDOMAttribute2 *iface, VARIANT_BOOL *fChildren)
418 {
419     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
420     FIXME("(%p)->(%p)\n", This, fChildren);
421     return E_NOTIMPL;
422 }
423 
424 static HRESULT WINAPI HTMLDOMAttribute2_cloneNode(IHTMLDOMAttribute2 *iface, VARIANT_BOOL fDeep,
425         IHTMLDOMAttribute **clonedNode)
426 {
427     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
428     FIXME("(%p)->(%x %p)\n", This, fDeep, clonedNode);
429     return E_NOTIMPL;
430 }
431 
432 static const IHTMLDOMAttribute2Vtbl HTMLDOMAttribute2Vtbl = {
433     HTMLDOMAttribute2_QueryInterface,
434     HTMLDOMAttribute2_AddRef,
435     HTMLDOMAttribute2_Release,
436     HTMLDOMAttribute2_GetTypeInfoCount,
437     HTMLDOMAttribute2_GetTypeInfo,
438     HTMLDOMAttribute2_GetIDsOfNames,
439     HTMLDOMAttribute2_Invoke,
440     HTMLDOMAttribute2_get_name,
441     HTMLDOMAttribute2_put_value,
442     HTMLDOMAttribute2_get_value,
443     HTMLDOMAttribute2_get_expando,
444     HTMLDOMAttribute2_get_nodeType,
445     HTMLDOMAttribute2_get_parentNode,
446     HTMLDOMAttribute2_get_childNodes,
447     HTMLDOMAttribute2_get_firstChild,
448     HTMLDOMAttribute2_get_lastChild,
449     HTMLDOMAttribute2_get_previousSibling,
450     HTMLDOMAttribute2_get_nextSibling,
451     HTMLDOMAttribute2_get_attributes,
452     HTMLDOMAttribute2_get_ownerDocument,
453     HTMLDOMAttribute2_insertBefore,
454     HTMLDOMAttribute2_replaceChild,
455     HTMLDOMAttribute2_removeChild,
456     HTMLDOMAttribute2_appendChild,
457     HTMLDOMAttribute2_hasChildNodes,
458     HTMLDOMAttribute2_cloneNode
459 };
460 
461 static const tid_t HTMLDOMAttribute_iface_tids[] = {
462     IHTMLDOMAttribute_tid,
463     IHTMLDOMAttribute2_tid,
464     0
465 };
466 static dispex_static_data_t HTMLDOMAttribute_dispex = {
467     NULL,
468     DispHTMLDOMAttribute_tid,
469     0,
470     HTMLDOMAttribute_iface_tids
471 };
472 
473 HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dispid, HTMLDOMAttribute **attr)
474 {
475     HTMLAttributeCollection *col;
476     HTMLDOMAttribute *ret;
477     HRESULT hres;
478 
479     ret = heap_alloc_zero(sizeof(*ret));
480     if(!ret)
481         return E_OUTOFMEMORY;
482 
483     ret->IHTMLDOMAttribute_iface.lpVtbl = &HTMLDOMAttributeVtbl;
484     ret->IHTMLDOMAttribute2_iface.lpVtbl = &HTMLDOMAttribute2Vtbl;
485     ret->ref = 1;
486     ret->dispid = dispid;
487     ret->elem = elem;
488 
489     init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLDOMAttribute_iface,
490             &HTMLDOMAttribute_dispex);
491 
492     /* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */
493     if(elem) {
494         hres = HTMLElement_get_attr_col(&elem->node, &col);
495         if(FAILED(hres)) {
496             IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
497             return hres;
498         }
499         IHTMLAttributeCollection_Release(&col->IHTMLAttributeCollection_iface);
500 
501         list_add_tail(&elem->attrs->attrs, &ret->entry);
502     }
503 
504     /* For detached attributes we may still do most operations if we have its name available. */
505     if(name) {
506         ret->name = heap_strdupW(name);
507         if(!ret->name) {
508             IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
509             return E_OUTOFMEMORY;
510         }
511     }
512 
513     *attr = ret;
514     return S_OK;
515 }
516