crypt32: NULL ptr could leak into function (Coverity).
[wine] / dlls / mshtml / htmlform.c
1 /*
2  * Copyright 2009 Andrew Eikum 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 <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27
28 #include "wine/debug.h"
29
30 #include "mshtml_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
33
34 struct HTMLFormElement {
35     HTMLElement element;
36
37     const IHTMLFormElementVtbl *lpHTMLFormElementVtbl;
38
39     nsIDOMHTMLFormElement *nsform;
40 };
41
42 #define HTMLFORM(x)  (&(x)->lpHTMLFormElementVtbl)
43
44 static HRESULT htmlform_item(HTMLFormElement *This, int i, IDispatch **ret)
45 {
46     nsIDOMHTMLCollection *elements;
47     nsIDOMNode *item;
48     HTMLDOMNode *node;
49     nsresult nsres;
50     HRESULT hres;
51
52     nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
53     if(NS_FAILED(nsres)) {
54         FIXME("GetElements failed: 0x%08x\n", nsres);
55         return E_FAIL;
56     }
57
58     nsres = nsIDOMHTMLCollection_Item(elements, i, &item);
59     nsIDOMHTMLCollection_Release(elements);
60     if(NS_FAILED(nsres)) {
61         FIXME("Item failed: 0x%08x\n", nsres);
62         return E_FAIL;
63     }
64
65     if(item) {
66         hres = get_node(This->element.node.doc, item, TRUE, &node);
67         if(FAILED(hres))
68             return hres;
69
70         IHTMLDOMNode_AddRef(&node->IHTMLDOMNode_iface);
71         nsIDOMNode_Release(item);
72         *ret = (IDispatch*)&node->IHTMLDOMNode_iface;
73     }else {
74         *ret = NULL;
75     }
76
77     return S_OK;
78 }
79
80 #define HTMLFORM_THIS(iface) DEFINE_THIS(HTMLFormElement, HTMLFormElement, iface)
81
82 static HRESULT WINAPI HTMLFormElement_QueryInterface(IHTMLFormElement *iface,
83         REFIID riid, void **ppv)
84 {
85     HTMLFormElement *This = HTMLFORM_THIS(iface);
86
87     return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv);
88 }
89
90 static ULONG WINAPI HTMLFormElement_AddRef(IHTMLFormElement *iface)
91 {
92     HTMLFormElement *This = HTMLFORM_THIS(iface);
93
94     return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface);
95 }
96
97 static ULONG WINAPI HTMLFormElement_Release(IHTMLFormElement *iface)
98 {
99     HTMLFormElement *This = HTMLFORM_THIS(iface);
100
101     return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface);
102 }
103
104 static HRESULT WINAPI HTMLFormElement_GetTypeInfoCount(IHTMLFormElement *iface, UINT *pctinfo)
105 {
106     HTMLFormElement *This = HTMLFORM_THIS(iface);
107     return IDispatchEx_GetTypeInfoCount(&This->element.node.dispex.IDispatchEx_iface, pctinfo);
108 }
109
110 static HRESULT WINAPI HTMLFormElement_GetTypeInfo(IHTMLFormElement *iface, UINT iTInfo,
111                                               LCID lcid, ITypeInfo **ppTInfo)
112 {
113     HTMLFormElement *This = HTMLFORM_THIS(iface);
114     return IDispatchEx_GetTypeInfo(&This->element.node.dispex.IDispatchEx_iface, iTInfo, lcid,
115             ppTInfo);
116 }
117
118 static HRESULT WINAPI HTMLFormElement_GetIDsOfNames(IHTMLFormElement *iface, REFIID riid,
119                                                 LPOLESTR *rgszNames, UINT cNames,
120                                                 LCID lcid, DISPID *rgDispId)
121 {
122     HTMLFormElement *This = HTMLFORM_THIS(iface);
123     return IDispatchEx_GetIDsOfNames(&This->element.node.dispex.IDispatchEx_iface, riid, rgszNames,
124             cNames, lcid, rgDispId);
125 }
126
127 static HRESULT WINAPI HTMLFormElement_Invoke(IHTMLFormElement *iface, DISPID dispIdMember,
128                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
129                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
130 {
131     HTMLFormElement *This = HTMLFORM_THIS(iface);
132     return IDispatchEx_Invoke(&This->element.node.dispex.IDispatchEx_iface, dispIdMember, riid,
133             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
134 }
135
136 static HRESULT WINAPI HTMLFormElement_put_action(IHTMLFormElement *iface, BSTR v)
137 {
138     HTMLFormElement *This = HTMLFORM_THIS(iface);
139     nsAString action_str;
140     nsresult nsres;
141
142     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
143
144     nsAString_InitDepend(&action_str, v);
145     nsres = nsIDOMHTMLFormElement_SetAction(This->nsform, &action_str);
146     nsAString_Finish(&action_str);
147     if(NS_FAILED(nsres)) {
148         ERR("SetAction failed: %08x\n", nsres);
149         return E_FAIL;
150     }
151
152     return S_OK;
153 }
154
155 static HRESULT WINAPI HTMLFormElement_get_action(IHTMLFormElement *iface, BSTR *p)
156 {
157     HTMLFormElement *This = HTMLFORM_THIS(iface);
158     nsAString action_str;
159     nsresult nsres;
160     HRESULT hres;
161
162     TRACE("(%p)->(%p)\n", This, p);
163
164     nsAString_Init(&action_str, NULL);
165     nsres = nsIDOMHTMLFormElement_GetAction(This->nsform, &action_str);
166     if(NS_SUCCEEDED(nsres)) {
167         const PRUnichar *action;
168         nsAString_GetData(&action_str, &action);
169         hres = nsuri_to_url(action, FALSE, p);
170     }else {
171         ERR("GetAction failed: %08x\n", nsres);
172         hres = E_FAIL;
173     }
174
175     return hres;
176 }
177
178 static HRESULT WINAPI HTMLFormElement_put_dir(IHTMLFormElement *iface, BSTR v)
179 {
180     HTMLFormElement *This = HTMLFORM_THIS(iface);
181     FIXME("(%p)->(%s)\n", This, wine_dbgstr_w(v));
182     return E_NOTIMPL;
183 }
184
185 static HRESULT WINAPI HTMLFormElement_get_dir(IHTMLFormElement *iface, BSTR *p)
186 {
187     HTMLFormElement *This = HTMLFORM_THIS(iface);
188     FIXME("(%p)->(%p)\n", This, p);
189     return E_NOTIMPL;
190 }
191
192 static HRESULT WINAPI HTMLFormElement_put_encoding(IHTMLFormElement *iface, BSTR v)
193 {
194     static const WCHAR urlencodedW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
195         'x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o','d','e','d',0};
196     static const WCHAR dataW[] = {'m','u','l','t','i','p','a','r','t','/',
197         'f','o','r','m','-','d','a','t','a',0};
198     static const WCHAR plainW[] = {'t','e','x','t','/','p','l','a','i','n',0};
199
200     HTMLFormElement *This = HTMLFORM_THIS(iface);
201     nsAString encoding_str;
202     nsresult nsres;
203
204     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
205
206     if(lstrcmpiW(v, urlencodedW) && lstrcmpiW(v, dataW) && lstrcmpiW(v, plainW)) {
207         WARN("incorrect enctype\n");
208         return E_INVALIDARG;
209     }
210
211     nsAString_InitDepend(&encoding_str, v);
212     nsres = nsIDOMHTMLFormElement_SetEnctype(This->nsform, &encoding_str);
213     nsAString_Finish(&encoding_str);
214     if(NS_FAILED(nsres))
215         return E_FAIL;
216
217     return S_OK;
218 }
219
220 static HRESULT WINAPI HTMLFormElement_get_encoding(IHTMLFormElement *iface, BSTR *p)
221 {
222     HTMLFormElement *This = HTMLFORM_THIS(iface);
223     nsAString encoding_str;
224     nsresult nsres;
225
226     TRACE("(%p)->(%p)\n", This, p);
227
228     nsAString_Init(&encoding_str, NULL);
229     nsres = nsIDOMHTMLFormElement_GetEnctype(This->nsform, &encoding_str);
230     if(NS_SUCCEEDED(nsres)) {
231         const PRUnichar *encoding;
232         nsAString_GetData(&encoding_str, &encoding);
233
234         *p = SysAllocString(encoding);
235         if(!*p)
236             return E_OUTOFMEMORY;
237     }else
238         return E_FAIL;
239
240     return S_OK;
241 }
242
243 static HRESULT WINAPI HTMLFormElement_put_method(IHTMLFormElement *iface, BSTR v)
244 {
245     static const WCHAR postW[] = {'P','O','S','T',0};
246     static const WCHAR getW[] = {'G','E','T',0};
247
248     HTMLFormElement *This = HTMLFORM_THIS(iface);
249     nsAString method_str;
250     nsresult nsres;
251
252     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
253
254     if(lstrcmpiW(v, postW) && lstrcmpiW(v, getW)) {
255         WARN("unrecognized method\n");
256         return E_INVALIDARG;
257     }
258
259     nsAString_InitDepend(&method_str, v);
260     nsres = nsIDOMHTMLFormElement_SetMethod(This->nsform, &method_str);
261     nsAString_Finish(&method_str);
262     if(NS_FAILED(nsres))
263         return E_FAIL;
264
265     return S_OK;
266 }
267
268 static HRESULT WINAPI HTMLFormElement_get_method(IHTMLFormElement *iface, BSTR *p)
269 {
270     HTMLFormElement *This = HTMLFORM_THIS(iface);
271     nsAString method_str;
272     nsresult nsres;
273
274     TRACE("(%p)->(%p)\n", This, p);
275
276     nsAString_Init(&method_str, NULL);
277     nsres = nsIDOMHTMLFormElement_GetMethod(This->nsform, &method_str);
278     if(NS_SUCCEEDED(nsres)) {
279         const PRUnichar *method;
280         nsAString_GetData(&method_str, &method);
281
282         *p = SysAllocString(method);
283         if(!*p)
284             return E_OUTOFMEMORY;
285     }else
286         return E_FAIL;
287
288     return S_OK;
289 }
290
291 static HRESULT WINAPI HTMLFormElement_get_elements(IHTMLFormElement *iface, IDispatch **p)
292 {
293     HTMLFormElement *This = HTMLFORM_THIS(iface);
294     FIXME("(%p)->(%p)\n", This, p);
295     return E_NOTIMPL;
296 }
297
298 static HRESULT WINAPI HTMLFormElement_put_target(IHTMLFormElement *iface, BSTR v)
299 {
300     HTMLFormElement *This = HTMLFORM_THIS(iface);
301     FIXME("(%p)->(%s)\n", This, wine_dbgstr_w(v));
302     return E_NOTIMPL;
303 }
304
305 static HRESULT WINAPI HTMLFormElement_get_target(IHTMLFormElement *iface, BSTR *p)
306 {
307     HTMLFormElement *This = HTMLFORM_THIS(iface);
308     FIXME("(%p)->(%p)\n", This, p);
309     return E_NOTIMPL;
310 }
311
312 static HRESULT WINAPI HTMLFormElement_put_name(IHTMLFormElement *iface, BSTR v)
313 {
314     HTMLFormElement *This = HTMLFORM_THIS(iface);
315     nsAString name_str;
316     nsresult nsres;
317
318     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
319
320     nsAString_InitDepend(&name_str, v);
321     nsres = nsIDOMHTMLFormElement_SetName(This->nsform, &name_str);
322     nsAString_Finish(&name_str);
323     if(NS_FAILED(nsres))
324         return E_FAIL;
325
326     return S_OK;
327 }
328
329 static HRESULT WINAPI HTMLFormElement_get_name(IHTMLFormElement *iface, BSTR *p)
330 {
331     HTMLFormElement *This = HTMLFORM_THIS(iface);
332     nsAString name_str;
333     nsresult nsres;
334
335     TRACE("(%p)->(%p)\n", This, p);
336
337     nsAString_Init(&name_str, NULL);
338     nsres = nsIDOMHTMLFormElement_GetName(This->nsform, &name_str);
339     if(NS_SUCCEEDED(nsres)) {
340         const PRUnichar *name;
341         nsAString_GetData(&name_str, &name);
342
343         if(*name) {
344             *p = SysAllocString(name);
345             if(!*p)
346                 return E_OUTOFMEMORY;
347         }else
348             *p = NULL;
349     }else
350         return E_FAIL;
351
352     return S_OK;
353 }
354
355 static HRESULT WINAPI HTMLFormElement_put_onsubmit(IHTMLFormElement *iface, VARIANT v)
356 {
357     HTMLFormElement *This = HTMLFORM_THIS(iface);
358     FIXME("(%p)->(v)\n", This);
359     return E_NOTIMPL;
360 }
361
362 static HRESULT WINAPI HTMLFormElement_get_onsubmit(IHTMLFormElement *iface, VARIANT *p)
363 {
364     HTMLFormElement *This = HTMLFORM_THIS(iface);
365     FIXME("(%p)->(%p)\n", This, p);
366     return E_NOTIMPL;
367 }
368
369 static HRESULT WINAPI HTMLFormElement_put_onreset(IHTMLFormElement *iface, VARIANT v)
370 {
371     HTMLFormElement *This = HTMLFORM_THIS(iface);
372     FIXME("(%p)->(v)\n", This);
373     return E_NOTIMPL;
374 }
375
376 static HRESULT WINAPI HTMLFormElement_get_onreset(IHTMLFormElement *iface, VARIANT *p)
377 {
378     HTMLFormElement *This = HTMLFORM_THIS(iface);
379     FIXME("(%p)->(%p)\n", This, p);
380     return E_NOTIMPL;
381 }
382
383 static HRESULT WINAPI HTMLFormElement_submit(IHTMLFormElement *iface)
384 {
385     HTMLFormElement *This = HTMLFORM_THIS(iface);
386     FIXME("(%p)->()\n", This);
387     return E_NOTIMPL;
388 }
389
390 static HRESULT WINAPI HTMLFormElement_reset(IHTMLFormElement *iface)
391 {
392     HTMLFormElement *This = HTMLFORM_THIS(iface);
393     FIXME("(%p)->()\n", This);
394     return E_NOTIMPL;
395 }
396
397 static HRESULT WINAPI HTMLFormElement_put_length(IHTMLFormElement *iface, LONG v)
398 {
399     HTMLFormElement *This = HTMLFORM_THIS(iface);
400     FIXME("(%p)->(%d)\n", This, v);
401     return E_NOTIMPL;
402 }
403
404 static HRESULT WINAPI HTMLFormElement_get_length(IHTMLFormElement *iface, LONG *p)
405 {
406     HTMLFormElement *This = HTMLFORM_THIS(iface);
407     PRInt32 length;
408     nsresult nsres;
409
410     TRACE("(%p)->(%p)\n", This, p);
411
412     nsres = nsIDOMHTMLFormElement_GetLength(This->nsform, &length);
413     if(NS_FAILED(nsres)) {
414         ERR("GetLength failed: %08x\n", nsres);
415         return E_FAIL;
416     }
417
418     *p = length;
419     return S_OK;
420 }
421
422 static HRESULT WINAPI HTMLFormElement__newEnum(IHTMLFormElement *iface, IUnknown **p)
423 {
424     HTMLFormElement *This = HTMLFORM_THIS(iface);
425     FIXME("(%p)->(%p)\n", This, p);
426     return E_NOTIMPL;
427 }
428
429 static HRESULT WINAPI HTMLFormElement_item(IHTMLFormElement *iface, VARIANT name,
430         VARIANT index, IDispatch **pdisp)
431 {
432     HTMLFormElement *This = HTMLFORM_THIS(iface);
433
434     TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
435
436     if(!pdisp)
437         return E_INVALIDARG;
438     *pdisp = NULL;
439
440     if(V_VT(&name) == VT_I4) {
441         if(V_I4(&name) < 0)
442             return E_INVALIDARG;
443         return htmlform_item(This, V_I4(&name), pdisp);
444     }
445
446     FIXME("Unsupported args\n");
447     return E_NOTIMPL;
448 }
449
450 static HRESULT WINAPI HTMLFormElement_tags(IHTMLFormElement *iface, VARIANT tagName,
451         IDispatch **pdisp)
452 {
453     HTMLFormElement *This = HTMLFORM_THIS(iface);
454     FIXME("(%p)->(v %p)\n", This, pdisp);
455     return E_NOTIMPL;
456 }
457
458 #undef HTMLFORM_THIS
459
460 static const IHTMLFormElementVtbl HTMLFormElementVtbl = {
461     HTMLFormElement_QueryInterface,
462     HTMLFormElement_AddRef,
463     HTMLFormElement_Release,
464     HTMLFormElement_GetTypeInfoCount,
465     HTMLFormElement_GetTypeInfo,
466     HTMLFormElement_GetIDsOfNames,
467     HTMLFormElement_Invoke,
468     HTMLFormElement_put_action,
469     HTMLFormElement_get_action,
470     HTMLFormElement_put_dir,
471     HTMLFormElement_get_dir,
472     HTMLFormElement_put_encoding,
473     HTMLFormElement_get_encoding,
474     HTMLFormElement_put_method,
475     HTMLFormElement_get_method,
476     HTMLFormElement_get_elements,
477     HTMLFormElement_put_target,
478     HTMLFormElement_get_target,
479     HTMLFormElement_put_name,
480     HTMLFormElement_get_name,
481     HTMLFormElement_put_onsubmit,
482     HTMLFormElement_get_onsubmit,
483     HTMLFormElement_put_onreset,
484     HTMLFormElement_get_onreset,
485     HTMLFormElement_submit,
486     HTMLFormElement_reset,
487     HTMLFormElement_put_length,
488     HTMLFormElement_get_length,
489     HTMLFormElement__newEnum,
490     HTMLFormElement_item,
491     HTMLFormElement_tags
492 };
493
494 static inline HTMLFormElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface)
495 {
496     return CONTAINING_RECORD(iface, HTMLFormElement, element.node);
497 }
498
499 static HRESULT HTMLFormElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
500 {
501     HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
502
503     *ppv = NULL;
504
505     if(IsEqualGUID(&IID_IUnknown, riid)) {
506         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
507         *ppv = HTMLFORM(This);
508     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
509         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
510         *ppv = HTMLFORM(This);
511     }else if(IsEqualGUID(&IID_IHTMLFormElement, riid)) {
512         TRACE("(%p)->(IID_IHTMLFormElement %p)\n", This, ppv);
513         *ppv = HTMLFORM(This);
514     }
515
516     if(*ppv) {
517         IUnknown_AddRef((IUnknown*)*ppv);
518         return S_OK;
519     }
520
521     return HTMLElement_QI(&This->element.node, riid, ppv);
522 }
523
524 static void HTMLFormElement_destructor(HTMLDOMNode *iface)
525 {
526     HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
527
528     if(This->nsform)
529         nsIDOMHTMLFormElement_Release(This->nsform);
530
531     HTMLElement_destructor(&This->element.node);
532 }
533
534 static HRESULT HTMLFormElement_get_dispid(HTMLDOMNode *iface,
535         BSTR name, DWORD grfdex, DISPID *pid)
536 {
537     HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
538     nsIDOMHTMLCollection *elements;
539     nsAString nsname, nsstr;
540     PRUint32 len, i;
541     nsresult nsres;
542     HRESULT hres = DISP_E_UNKNOWNNAME;
543
544     static const PRUnichar nameW[] = {'n','a','m','e',0};
545
546     TRACE("(%p)->(%s %x %p)\n", This, wine_dbgstr_w(name), grfdex, pid);
547
548     nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
549     if(NS_FAILED(nsres)) {
550         FIXME("GetElements failed: 0x%08x\n", nsres);
551         return E_FAIL;
552     }
553
554     nsres = nsIDOMHTMLCollection_GetLength(elements, &len);
555     if(NS_FAILED(nsres)) {
556         FIXME("GetLength failed: 0x%08x\n", nsres);
557         nsIDOMHTMLCollection_Release(elements);
558         return E_FAIL;
559     }
560
561     nsAString_InitDepend(&nsname, nameW);
562     nsAString_Init(&nsstr, NULL);
563     for(i = 0; i < len; ++i) {
564         nsIDOMNode *nsitem;
565         nsIDOMHTMLElement *nshtml_elem;
566         const PRUnichar *str;
567
568         nsres = nsIDOMHTMLCollection_Item(elements, i, &nsitem);
569         if(NS_FAILED(nsres)) {
570             FIXME("Item failed: 0x%08x\n", nsres);
571             hres = E_FAIL;
572             break;
573         }
574
575         nsres = nsIDOMNode_QueryInterface(nsitem, &IID_nsIDOMHTMLElement, (void**)&nshtml_elem);
576         nsIDOMNode_Release(nsitem);
577         if(NS_FAILED(nsres)) {
578             FIXME("Failed to get nsIDOMHTMLNode interface: 0x%08x\n", nsres);
579             hres = E_FAIL;
580             break;
581         }
582
583         /* compare by id attr */
584         nsres = nsIDOMHTMLElement_GetId(nshtml_elem, &nsstr);
585         if(NS_FAILED(nsres)) {
586             FIXME("GetId failed: 0x%08x\n", nsres);
587             nsIDOMHTMLElement_Release(nshtml_elem);
588             hres = E_FAIL;
589             break;
590         }
591         nsAString_GetData(&nsstr, &str);
592         if(!strcmpiW(str, name)) {
593             nsIDOMHTMLElement_Release(nshtml_elem);
594             /* FIXME: using index for dispid */
595             *pid = MSHTML_DISPID_CUSTOM_MIN + i;
596             hres = S_OK;
597             break;
598         }
599
600         /* compare by name attr */
601         nsres = nsIDOMHTMLElement_GetAttribute(nshtml_elem, &nsname, &nsstr);
602         nsIDOMHTMLElement_Release(nshtml_elem);
603         nsAString_GetData(&nsstr, &str);
604         if(!strcmpiW(str, name)) {
605             /* FIXME: using index for dispid */
606             *pid = MSHTML_DISPID_CUSTOM_MIN + i;
607             hres = S_OK;
608             break;
609         }
610     }
611     nsAString_Finish(&nsname);
612     nsAString_Finish(&nsstr);
613
614     nsIDOMHTMLCollection_Release(elements);
615
616     return hres;
617 }
618
619 static HRESULT HTMLFormElement_invoke(HTMLDOMNode *iface,
620         DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res,
621         EXCEPINFO *ei, IServiceProvider *caller)
622 {
623     HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
624     IDispatch *ret;
625     HRESULT hres;
626
627     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
628
629     hres = htmlform_item(This, id - MSHTML_DISPID_CUSTOM_MIN, &ret);
630     if(FAILED(hres))
631         return hres;
632
633     if(ret) {
634         V_VT(res) = VT_DISPATCH;
635         V_DISPATCH(res) = ret;
636     }else {
637         V_VT(res) = VT_NULL;
638     }
639     return S_OK;
640 }
641
642 static const NodeImplVtbl HTMLFormElementImplVtbl = {
643     HTMLFormElement_QI,
644     HTMLFormElement_destructor,
645     HTMLElement_clone,
646     NULL,
647     NULL,
648     NULL,
649     NULL,
650     NULL,
651     NULL,
652     HTMLFormElement_get_dispid,
653     HTMLFormElement_invoke
654 };
655
656 static const tid_t HTMLFormElement_iface_tids[] = {
657     HTMLELEMENT_TIDS,
658     IHTMLFormElement_tid,
659     0
660 };
661
662 static dispex_static_data_t HTMLFormElement_dispex = {
663     NULL,
664     DispHTMLFormElement_tid,
665     NULL,
666     HTMLFormElement_iface_tids
667 };
668
669 HRESULT HTMLFormElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem, HTMLElement **elem)
670 {
671     HTMLFormElement *ret;
672     nsresult nsres;
673
674     ret = heap_alloc_zero(sizeof(HTMLFormElement));
675     if(!ret)
676         return E_OUTOFMEMORY;
677
678     ret->lpHTMLFormElementVtbl = &HTMLFormElementVtbl;
679     ret->element.node.vtbl = &HTMLFormElementImplVtbl;
680
681     nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLFormElement, (void**)&ret->nsform);
682     if(NS_FAILED(nsres)) {
683         ERR("Could not get nsIDOMHTMLFormElement interface: %08x\n", nsres);
684         heap_free(ret);
685         return E_FAIL;
686     }
687
688     HTMLElement_Init(&ret->element, doc, nselem, &HTMLFormElement_dispex);
689
690     *elem = &ret->element;
691     return S_OK;
692 }