mshtml: Keep reference in node returned from get_node.
[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 #include "htmlevent.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
34
35 struct HTMLFormElement {
36     HTMLElement element;
37
38     IHTMLFormElement IHTMLFormElement_iface;
39
40     nsIDOMHTMLFormElement *nsform;
41 };
42
43 static HRESULT htmlform_item(HTMLFormElement *This, int i, IDispatch **ret)
44 {
45     nsIDOMHTMLCollection *elements;
46     nsIDOMNode *item;
47     HTMLDOMNode *node;
48     nsresult nsres;
49     HRESULT hres;
50
51     nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
52     if(NS_FAILED(nsres)) {
53         FIXME("GetElements failed: 0x%08x\n", nsres);
54         return E_FAIL;
55     }
56
57     nsres = nsIDOMHTMLCollection_Item(elements, i, &item);
58     nsIDOMHTMLCollection_Release(elements);
59     if(NS_FAILED(nsres)) {
60         FIXME("Item failed: 0x%08x\n", nsres);
61         return E_FAIL;
62     }
63
64     if(item) {
65         hres = get_node(This->element.node.doc, item, TRUE, &node);
66         if(FAILED(hres))
67             return hres;
68
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     nsAString_Finish(&action_str);
177     return hres;
178 }
179
180 static HRESULT WINAPI HTMLFormElement_put_dir(IHTMLFormElement *iface, BSTR v)
181 {
182     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
183     FIXME("(%p)->(%s)\n", This, wine_dbgstr_w(v));
184     return E_NOTIMPL;
185 }
186
187 static HRESULT WINAPI HTMLFormElement_get_dir(IHTMLFormElement *iface, BSTR *p)
188 {
189     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
190     FIXME("(%p)->(%p)\n", This, p);
191     return E_NOTIMPL;
192 }
193
194 static HRESULT WINAPI HTMLFormElement_put_encoding(IHTMLFormElement *iface, BSTR v)
195 {
196     static const WCHAR urlencodedW[] = {'a','p','p','l','i','c','a','t','i','o','n','/',
197         'x','-','w','w','w','-','f','o','r','m','-','u','r','l','e','n','c','o','d','e','d',0};
198     static const WCHAR dataW[] = {'m','u','l','t','i','p','a','r','t','/',
199         'f','o','r','m','-','d','a','t','a',0};
200     static const WCHAR plainW[] = {'t','e','x','t','/','p','l','a','i','n',0};
201
202     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
203     nsAString encoding_str;
204     nsresult nsres;
205
206     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
207
208     if(lstrcmpiW(v, urlencodedW) && lstrcmpiW(v, dataW) && lstrcmpiW(v, plainW)) {
209         WARN("incorrect enctype\n");
210         return E_INVALIDARG;
211     }
212
213     nsAString_InitDepend(&encoding_str, v);
214     nsres = nsIDOMHTMLFormElement_SetEnctype(This->nsform, &encoding_str);
215     nsAString_Finish(&encoding_str);
216     if(NS_FAILED(nsres))
217         return E_FAIL;
218
219     return S_OK;
220 }
221
222 static HRESULT WINAPI HTMLFormElement_get_encoding(IHTMLFormElement *iface, BSTR *p)
223 {
224     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
225     nsAString encoding_str;
226     nsresult nsres;
227
228     TRACE("(%p)->(%p)\n", This, p);
229
230     nsAString_Init(&encoding_str, NULL);
231     nsres = nsIDOMHTMLFormElement_GetEnctype(This->nsform, &encoding_str);
232     return return_nsstr(nsres, &encoding_str, p);
233 }
234
235 static HRESULT WINAPI HTMLFormElement_put_method(IHTMLFormElement *iface, BSTR v)
236 {
237     static const WCHAR postW[] = {'P','O','S','T',0};
238     static const WCHAR getW[] = {'G','E','T',0};
239
240     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
241     nsAString method_str;
242     nsresult nsres;
243
244     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
245
246     if(lstrcmpiW(v, postW) && lstrcmpiW(v, getW)) {
247         WARN("unrecognized method\n");
248         return E_INVALIDARG;
249     }
250
251     nsAString_InitDepend(&method_str, v);
252     nsres = nsIDOMHTMLFormElement_SetMethod(This->nsform, &method_str);
253     nsAString_Finish(&method_str);
254     if(NS_FAILED(nsres))
255         return E_FAIL;
256
257     return S_OK;
258 }
259
260 static HRESULT WINAPI HTMLFormElement_get_method(IHTMLFormElement *iface, BSTR *p)
261 {
262     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
263     nsAString method_str;
264     nsresult nsres;
265
266     TRACE("(%p)->(%p)\n", This, p);
267
268     nsAString_Init(&method_str, NULL);
269     nsres = nsIDOMHTMLFormElement_GetMethod(This->nsform, &method_str);
270     return return_nsstr(nsres, &method_str, p);
271 }
272
273 static HRESULT WINAPI HTMLFormElement_get_elements(IHTMLFormElement *iface, IDispatch **p)
274 {
275     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
276
277     TRACE("(%p)->(%p)\n", This, p);
278
279     *p = (IDispatch*)&This->IHTMLFormElement_iface;
280     IDispatch_AddRef(*p);
281     return S_OK;
282 }
283
284 static HRESULT WINAPI HTMLFormElement_put_target(IHTMLFormElement *iface, BSTR v)
285 {
286     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
287     FIXME("(%p)->(%s)\n", This, wine_dbgstr_w(v));
288     return E_NOTIMPL;
289 }
290
291 static HRESULT WINAPI HTMLFormElement_get_target(IHTMLFormElement *iface, BSTR *p)
292 {
293     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
294     FIXME("(%p)->(%p)\n", This, p);
295     return E_NOTIMPL;
296 }
297
298 static HRESULT WINAPI HTMLFormElement_put_name(IHTMLFormElement *iface, BSTR v)
299 {
300     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
301     nsAString name_str;
302     nsresult nsres;
303
304     TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
305
306     nsAString_InitDepend(&name_str, v);
307     nsres = nsIDOMHTMLFormElement_SetName(This->nsform, &name_str);
308     nsAString_Finish(&name_str);
309     if(NS_FAILED(nsres))
310         return E_FAIL;
311
312     return S_OK;
313 }
314
315 static HRESULT WINAPI HTMLFormElement_get_name(IHTMLFormElement *iface, BSTR *p)
316 {
317     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
318     nsAString name_str;
319     nsresult nsres;
320
321     TRACE("(%p)->(%p)\n", This, p);
322
323     nsAString_Init(&name_str, NULL);
324     nsres = nsIDOMHTMLFormElement_GetName(This->nsform, &name_str);
325     return return_nsstr(nsres, &name_str, p);
326 }
327
328 static HRESULT WINAPI HTMLFormElement_put_onsubmit(IHTMLFormElement *iface, VARIANT v)
329 {
330     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
331
332     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
333
334     return set_node_event(&This->element.node, EVENTID_SUBMIT, &v);
335 }
336
337 static HRESULT WINAPI HTMLFormElement_get_onsubmit(IHTMLFormElement *iface, VARIANT *p)
338 {
339     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
340
341     TRACE("(%p)->(%p)\n", This, p);
342
343     return get_node_event(&This->element.node, EVENTID_SUBMIT, p);
344 }
345
346 static HRESULT WINAPI HTMLFormElement_put_onreset(IHTMLFormElement *iface, VARIANT v)
347 {
348     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
349     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
350     return E_NOTIMPL;
351 }
352
353 static HRESULT WINAPI HTMLFormElement_get_onreset(IHTMLFormElement *iface, VARIANT *p)
354 {
355     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
356     FIXME("(%p)->(%p)\n", This, p);
357     return E_NOTIMPL;
358 }
359
360 static HRESULT WINAPI HTMLFormElement_submit(IHTMLFormElement *iface)
361 {
362     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
363     nsresult nsres;
364
365     TRACE("(%p)->()\n", This);
366
367     nsres = nsIDOMHTMLFormElement_Submit(This->nsform);
368     if(NS_FAILED(nsres)) {
369         ERR("Submit failed: %08x\n", nsres);
370         return E_FAIL;
371     }
372
373     return S_OK;
374 }
375
376 static HRESULT WINAPI HTMLFormElement_reset(IHTMLFormElement *iface)
377 {
378     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
379     FIXME("(%p)->()\n", This);
380     return E_NOTIMPL;
381 }
382
383 static HRESULT WINAPI HTMLFormElement_put_length(IHTMLFormElement *iface, LONG v)
384 {
385     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
386     FIXME("(%p)->(%d)\n", This, v);
387     return E_NOTIMPL;
388 }
389
390 static HRESULT WINAPI HTMLFormElement_get_length(IHTMLFormElement *iface, LONG *p)
391 {
392     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
393     PRInt32 length;
394     nsresult nsres;
395
396     TRACE("(%p)->(%p)\n", This, p);
397
398     nsres = nsIDOMHTMLFormElement_GetLength(This->nsform, &length);
399     if(NS_FAILED(nsres)) {
400         ERR("GetLength failed: %08x\n", nsres);
401         return E_FAIL;
402     }
403
404     *p = length;
405     return S_OK;
406 }
407
408 static HRESULT WINAPI HTMLFormElement__newEnum(IHTMLFormElement *iface, IUnknown **p)
409 {
410     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
411     FIXME("(%p)->(%p)\n", This, p);
412     return E_NOTIMPL;
413 }
414
415 static HRESULT WINAPI HTMLFormElement_item(IHTMLFormElement *iface, VARIANT name,
416         VARIANT index, IDispatch **pdisp)
417 {
418     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
419
420     TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
421
422     if(!pdisp)
423         return E_INVALIDARG;
424     *pdisp = NULL;
425
426     if(V_VT(&name) == VT_I4) {
427         if(V_I4(&name) < 0)
428             return E_INVALIDARG;
429         return htmlform_item(This, V_I4(&name), pdisp);
430     }
431
432     FIXME("Unsupported args\n");
433     return E_NOTIMPL;
434 }
435
436 static HRESULT WINAPI HTMLFormElement_tags(IHTMLFormElement *iface, VARIANT tagName,
437         IDispatch **pdisp)
438 {
439     HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
440     FIXME("(%p)->(v %p)\n", This, pdisp);
441     return E_NOTIMPL;
442 }
443
444 static const IHTMLFormElementVtbl HTMLFormElementVtbl = {
445     HTMLFormElement_QueryInterface,
446     HTMLFormElement_AddRef,
447     HTMLFormElement_Release,
448     HTMLFormElement_GetTypeInfoCount,
449     HTMLFormElement_GetTypeInfo,
450     HTMLFormElement_GetIDsOfNames,
451     HTMLFormElement_Invoke,
452     HTMLFormElement_put_action,
453     HTMLFormElement_get_action,
454     HTMLFormElement_put_dir,
455     HTMLFormElement_get_dir,
456     HTMLFormElement_put_encoding,
457     HTMLFormElement_get_encoding,
458     HTMLFormElement_put_method,
459     HTMLFormElement_get_method,
460     HTMLFormElement_get_elements,
461     HTMLFormElement_put_target,
462     HTMLFormElement_get_target,
463     HTMLFormElement_put_name,
464     HTMLFormElement_get_name,
465     HTMLFormElement_put_onsubmit,
466     HTMLFormElement_get_onsubmit,
467     HTMLFormElement_put_onreset,
468     HTMLFormElement_get_onreset,
469     HTMLFormElement_submit,
470     HTMLFormElement_reset,
471     HTMLFormElement_put_length,
472     HTMLFormElement_get_length,
473     HTMLFormElement__newEnum,
474     HTMLFormElement_item,
475     HTMLFormElement_tags
476 };
477
478 static inline HTMLFormElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface)
479 {
480     return CONTAINING_RECORD(iface, HTMLFormElement, element.node);
481 }
482
483 static HRESULT HTMLFormElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
484 {
485     HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
486
487     *ppv = NULL;
488
489     if(IsEqualGUID(&IID_IUnknown, riid)) {
490         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
491         *ppv = &This->IHTMLFormElement_iface;
492     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
493         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
494         *ppv = &This->IHTMLFormElement_iface;
495     }else if(IsEqualGUID(&IID_IHTMLFormElement, riid)) {
496         TRACE("(%p)->(IID_IHTMLFormElement %p)\n", This, ppv);
497         *ppv = &This->IHTMLFormElement_iface;
498     }
499
500     if(*ppv) {
501         IUnknown_AddRef((IUnknown*)*ppv);
502         return S_OK;
503     }
504
505     return HTMLElement_QI(&This->element.node, riid, ppv);
506 }
507
508 static void HTMLFormElement_destructor(HTMLDOMNode *iface)
509 {
510     HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
511
512     if(This->nsform)
513         nsIDOMHTMLFormElement_Release(This->nsform);
514
515     HTMLElement_destructor(&This->element.node);
516 }
517
518 static HRESULT HTMLFormElement_get_dispid(HTMLDOMNode *iface,
519         BSTR name, DWORD grfdex, DISPID *pid)
520 {
521     HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
522     nsIDOMHTMLCollection *elements;
523     nsAString nsname, nsstr;
524     PRUint32 len, i;
525     nsresult nsres;
526     HRESULT hres = DISP_E_UNKNOWNNAME;
527
528     static const PRUnichar nameW[] = {'n','a','m','e',0};
529
530     TRACE("(%p)->(%s %x %p)\n", This, wine_dbgstr_w(name), grfdex, pid);
531
532     nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
533     if(NS_FAILED(nsres)) {
534         FIXME("GetElements failed: 0x%08x\n", nsres);
535         return E_FAIL;
536     }
537
538     nsres = nsIDOMHTMLCollection_GetLength(elements, &len);
539     if(NS_FAILED(nsres)) {
540         FIXME("GetLength failed: 0x%08x\n", nsres);
541         nsIDOMHTMLCollection_Release(elements);
542         return E_FAIL;
543     }
544
545     if(len > MSHTML_CUSTOM_DISPID_CNT)
546         len = MSHTML_CUSTOM_DISPID_CNT;
547
548     /* FIXME: Implement in more generic way */
549     if('0' <= *name && *name <= '9') {
550         WCHAR *end_ptr;
551
552         i = strtoulW(name, &end_ptr, 10);
553         if(!*end_ptr && i < len) {
554             *pid = MSHTML_DISPID_CUSTOM_MIN + i;
555             return S_OK;
556         }
557     }
558
559     nsAString_InitDepend(&nsname, nameW);
560     nsAString_Init(&nsstr, NULL);
561     for(i = 0; i < len; ++i) {
562         nsIDOMNode *nsitem;
563         nsIDOMHTMLElement *nshtml_elem;
564         const PRUnichar *str;
565
566         nsres = nsIDOMHTMLCollection_Item(elements, i, &nsitem);
567         if(NS_FAILED(nsres)) {
568             FIXME("Item failed: 0x%08x\n", nsres);
569             hres = E_FAIL;
570             break;
571         }
572
573         nsres = nsIDOMNode_QueryInterface(nsitem, &IID_nsIDOMHTMLElement, (void**)&nshtml_elem);
574         nsIDOMNode_Release(nsitem);
575         if(NS_FAILED(nsres)) {
576             FIXME("Failed to get nsIDOMHTMLNode interface: 0x%08x\n", nsres);
577             hres = E_FAIL;
578             break;
579         }
580
581         /* compare by id attr */
582         nsres = nsIDOMHTMLElement_GetId(nshtml_elem, &nsstr);
583         if(NS_FAILED(nsres)) {
584             FIXME("GetId failed: 0x%08x\n", nsres);
585             nsIDOMHTMLElement_Release(nshtml_elem);
586             hres = E_FAIL;
587             break;
588         }
589         nsAString_GetData(&nsstr, &str);
590         if(!strcmpiW(str, name)) {
591             nsIDOMHTMLElement_Release(nshtml_elem);
592             /* FIXME: using index for dispid */
593             *pid = MSHTML_DISPID_CUSTOM_MIN + i;
594             hres = S_OK;
595             break;
596         }
597
598         /* compare by name attr */
599         nsres = nsIDOMHTMLElement_GetAttribute(nshtml_elem, &nsname, &nsstr);
600         nsIDOMHTMLElement_Release(nshtml_elem);
601         nsAString_GetData(&nsstr, &str);
602         if(!strcmpiW(str, name)) {
603             /* FIXME: using index for dispid */
604             *pid = MSHTML_DISPID_CUSTOM_MIN + i;
605             hres = S_OK;
606             break;
607         }
608     }
609     nsAString_Finish(&nsname);
610     nsAString_Finish(&nsstr);
611
612     nsIDOMHTMLCollection_Release(elements);
613
614     return hres;
615 }
616
617 static HRESULT HTMLFormElement_invoke(HTMLDOMNode *iface,
618         DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res,
619         EXCEPINFO *ei, IServiceProvider *caller)
620 {
621     HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
622     IDispatch *ret;
623     HRESULT hres;
624
625     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
626
627     hres = htmlform_item(This, id - MSHTML_DISPID_CUSTOM_MIN, &ret);
628     if(FAILED(hres))
629         return hres;
630
631     if(ret) {
632         V_VT(res) = VT_DISPATCH;
633         V_DISPATCH(res) = ret;
634     }else {
635         V_VT(res) = VT_NULL;
636     }
637     return S_OK;
638 }
639
640 static const NodeImplVtbl HTMLFormElementImplVtbl = {
641     HTMLFormElement_QI,
642     HTMLFormElement_destructor,
643     HTMLElement_clone,
644     HTMLElement_get_attr_col,
645     NULL,
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->IHTMLFormElement_iface.lpVtbl = &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 }