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