wrc: Use ARRAY_SIZE instead of open coding it.
[wine.git] / dlls / mshtml / htmlform.c
blobd6e4b2d842483d64bd7591f889efd25d0262337b
1 /*
2 * Copyright 2009 Andrew Eikum for CodeWeavers
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.
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.
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
19 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
28 #include "wine/debug.h"
30 #include "mshtml_private.h"
31 #include "htmlevent.h"
32 #include "binding.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
36 struct HTMLFormElement {
37 HTMLElement element;
39 IHTMLFormElement IHTMLFormElement_iface;
41 nsIDOMHTMLFormElement *nsform;
44 typedef struct {
45 IEnumVARIANT IEnumVARIANT_iface;
47 LONG ref;
49 ULONG iter;
50 HTMLFormElement *elem;
51 } HTMLFormElementEnum;
53 HRESULT return_nsform(nsresult nsres, nsIDOMHTMLFormElement *form, IHTMLFormElement **p)
55 nsIDOMNode *form_node;
56 HTMLDOMNode *node;
57 HRESULT hres;
59 if (NS_FAILED(nsres)) {
60 ERR("GetForm failed: %08lx\n", nsres);
61 return E_FAIL;
64 if(!form) {
65 *p = NULL;
66 TRACE("NULL\n");
67 return S_OK;
70 nsres = nsIDOMHTMLFormElement_QueryInterface(form, &IID_nsIDOMNode, (void**)&form_node);
71 nsIDOMHTMLFormElement_Release(form);
72 assert(nsres == NS_OK);
74 hres = get_node(form_node, TRUE, &node);
75 nsIDOMNode_Release(form_node);
76 if (FAILED(hres))
77 return hres;
79 TRACE("node %p\n", node);
80 hres = IHTMLDOMNode_QueryInterface(&node->IHTMLDOMNode_iface, &IID_IHTMLFormElement, (void**)p);
81 node_release(node);
82 return hres;
85 static HRESULT htmlform_item(HTMLFormElement *This, int i, IDispatch **ret)
87 nsIDOMHTMLCollection *elements;
88 nsIDOMNode *item;
89 HTMLDOMNode *node;
90 nsresult nsres;
91 HRESULT hres;
93 nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
94 if(NS_FAILED(nsres)) {
95 FIXME("GetElements failed: 0x%08lx\n", nsres);
96 return E_FAIL;
99 nsres = nsIDOMHTMLCollection_Item(elements, i, &item);
100 nsIDOMHTMLCollection_Release(elements);
101 if(NS_FAILED(nsres)) {
102 FIXME("Item failed: 0x%08lx\n", nsres);
103 return E_FAIL;
106 if(item) {
107 hres = get_node(item, TRUE, &node);
108 if(FAILED(hres))
109 return hres;
111 nsIDOMNode_Release(item);
112 *ret = (IDispatch*)&node->IHTMLDOMNode_iface;
113 }else {
114 *ret = NULL;
117 return S_OK;
120 static inline HTMLFormElementEnum *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
122 return CONTAINING_RECORD(iface, HTMLFormElementEnum, IEnumVARIANT_iface);
125 static HRESULT WINAPI HTMLFormElementEnum_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
127 HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface);
129 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
131 if(IsEqualGUID(riid, &IID_IUnknown)) {
132 *ppv = &This->IEnumVARIANT_iface;
133 }else if(IsEqualGUID(riid, &IID_IEnumVARIANT)) {
134 *ppv = &This->IEnumVARIANT_iface;
135 }else {
136 FIXME("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
137 *ppv = NULL;
138 return E_NOINTERFACE;
141 IUnknown_AddRef((IUnknown*)*ppv);
142 return S_OK;
145 static ULONG WINAPI HTMLFormElementEnum_AddRef(IEnumVARIANT *iface)
147 HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface);
148 LONG ref = InterlockedIncrement(&This->ref);
150 TRACE("(%p) ref=%ld\n", This, ref);
152 return ref;
155 static ULONG WINAPI HTMLFormElementEnum_Release(IEnumVARIANT *iface)
157 HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface);
158 LONG ref = InterlockedDecrement(&This->ref);
160 TRACE("(%p) ref=%ld\n", This, ref);
162 if(!ref) {
163 IHTMLFormElement_Release(&This->elem->IHTMLFormElement_iface);
164 heap_free(This);
167 return ref;
170 static HRESULT WINAPI HTMLFormElementEnum_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
172 HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface);
173 nsresult nsres;
174 HRESULT hres;
175 ULONG num, i;
176 LONG len;
178 TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched);
180 nsres = nsIDOMHTMLFormElement_GetLength(This->elem->nsform, &len);
181 if(NS_FAILED(nsres))
182 return E_FAIL;
183 num = min(len - This->iter, celt);
185 for(i = 0; i < num; i++) {
186 hres = htmlform_item(This->elem, This->iter + i, &V_DISPATCH(&rgVar[i]));
187 if(FAILED(hres)) {
188 while(i--)
189 VariantClear(&rgVar[i]);
190 return hres;
192 V_VT(&rgVar[i]) = VT_DISPATCH;
195 This->iter += num;
196 if(pCeltFetched)
197 *pCeltFetched = num;
198 return num == celt ? S_OK : S_FALSE;
201 static HRESULT WINAPI HTMLFormElementEnum_Skip(IEnumVARIANT *iface, ULONG celt)
203 HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface);
204 nsresult nsres;
205 LONG len;
207 TRACE("(%p)->(%lu)\n", This, celt);
209 nsres = nsIDOMHTMLFormElement_GetLength(This->elem->nsform, &len);
210 if(NS_FAILED(nsres))
211 return E_FAIL;
213 if(This->iter + celt > len) {
214 This->iter = len;
215 return S_FALSE;
218 This->iter += celt;
219 return S_OK;
222 static HRESULT WINAPI HTMLFormElementEnum_Reset(IEnumVARIANT *iface)
224 HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface);
226 TRACE("(%p)->()\n", This);
228 This->iter = 0;
229 return S_OK;
232 static HRESULT WINAPI HTMLFormElementEnum_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
234 HTMLFormElementEnum *This = impl_from_IEnumVARIANT(iface);
235 FIXME("(%p)->(%p)\n", This, ppEnum);
236 return E_NOTIMPL;
239 static const IEnumVARIANTVtbl HTMLFormElementEnumVtbl = {
240 HTMLFormElementEnum_QueryInterface,
241 HTMLFormElementEnum_AddRef,
242 HTMLFormElementEnum_Release,
243 HTMLFormElementEnum_Next,
244 HTMLFormElementEnum_Skip,
245 HTMLFormElementEnum_Reset,
246 HTMLFormElementEnum_Clone
249 static inline HTMLFormElement *impl_from_IHTMLFormElement(IHTMLFormElement *iface)
251 return CONTAINING_RECORD(iface, HTMLFormElement, IHTMLFormElement_iface);
254 static HRESULT WINAPI HTMLFormElement_QueryInterface(IHTMLFormElement *iface,
255 REFIID riid, void **ppv)
257 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
259 return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv);
262 static ULONG WINAPI HTMLFormElement_AddRef(IHTMLFormElement *iface)
264 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
266 return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface);
269 static ULONG WINAPI HTMLFormElement_Release(IHTMLFormElement *iface)
271 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
273 return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface);
276 static HRESULT WINAPI HTMLFormElement_GetTypeInfoCount(IHTMLFormElement *iface, UINT *pctinfo)
278 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
279 return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo);
282 static HRESULT WINAPI HTMLFormElement_GetTypeInfo(IHTMLFormElement *iface, UINT iTInfo,
283 LCID lcid, ITypeInfo **ppTInfo)
285 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
286 return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid,
287 ppTInfo);
290 static HRESULT WINAPI HTMLFormElement_GetIDsOfNames(IHTMLFormElement *iface, REFIID riid,
291 LPOLESTR *rgszNames, UINT cNames,
292 LCID lcid, DISPID *rgDispId)
294 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
295 return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames,
296 cNames, lcid, rgDispId);
299 static HRESULT WINAPI HTMLFormElement_Invoke(IHTMLFormElement *iface, DISPID dispIdMember,
300 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
301 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
303 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
304 return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid,
305 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
308 static HRESULT WINAPI HTMLFormElement_put_action(IHTMLFormElement *iface, BSTR v)
310 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
311 nsAString action_str;
312 nsresult nsres;
314 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
316 nsAString_InitDepend(&action_str, v);
317 nsres = nsIDOMHTMLFormElement_SetAction(This->nsform, &action_str);
318 nsAString_Finish(&action_str);
319 if(NS_FAILED(nsres)) {
320 ERR("SetAction failed: %08lx\n", nsres);
321 return E_FAIL;
324 return S_OK;
327 static HRESULT WINAPI HTMLFormElement_get_action(IHTMLFormElement *iface, BSTR *p)
329 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
330 nsAString action_str;
331 nsresult nsres;
332 HRESULT hres;
334 TRACE("(%p)->(%p)\n", This, p);
336 nsAString_Init(&action_str, NULL);
337 nsres = nsIDOMHTMLFormElement_GetAction(This->nsform, &action_str);
338 if(NS_SUCCEEDED(nsres)) {
339 const PRUnichar *action;
340 nsAString_GetData(&action_str, &action);
341 hres = nsuri_to_url(action, FALSE, p);
342 }else {
343 ERR("GetAction failed: %08lx\n", nsres);
344 hres = E_FAIL;
347 nsAString_Finish(&action_str);
348 return hres;
351 static HRESULT WINAPI HTMLFormElement_put_dir(IHTMLFormElement *iface, BSTR v)
353 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
354 FIXME("(%p)->(%s)\n", This, wine_dbgstr_w(v));
355 return E_NOTIMPL;
358 static HRESULT WINAPI HTMLFormElement_get_dir(IHTMLFormElement *iface, BSTR *p)
360 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
361 FIXME("(%p)->(%p)\n", This, p);
362 return E_NOTIMPL;
365 static HRESULT WINAPI HTMLFormElement_put_encoding(IHTMLFormElement *iface, BSTR v)
367 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
368 nsAString encoding_str;
369 nsresult nsres;
371 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
373 if(lstrcmpiW(v, L"application/x-www-form-urlencoded") && lstrcmpiW(v, L"multipart/form-data")
374 && lstrcmpiW(v, L"text/plain")) {
375 WARN("incorrect enctype\n");
376 return E_INVALIDARG;
379 nsAString_InitDepend(&encoding_str, v);
380 nsres = nsIDOMHTMLFormElement_SetEnctype(This->nsform, &encoding_str);
381 nsAString_Finish(&encoding_str);
382 if(NS_FAILED(nsres))
383 return E_FAIL;
385 return S_OK;
388 static HRESULT WINAPI HTMLFormElement_get_encoding(IHTMLFormElement *iface, BSTR *p)
390 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
391 nsAString encoding_str;
392 nsresult nsres;
394 TRACE("(%p)->(%p)\n", This, p);
396 nsAString_Init(&encoding_str, NULL);
397 nsres = nsIDOMHTMLFormElement_GetEnctype(This->nsform, &encoding_str);
398 return return_nsstr(nsres, &encoding_str, p);
401 static HRESULT WINAPI HTMLFormElement_put_method(IHTMLFormElement *iface, BSTR v)
403 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
404 nsAString method_str;
405 nsresult nsres;
407 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
409 if(lstrcmpiW(v, L"POST") && lstrcmpiW(v, L"GET")) {
410 WARN("unrecognized method\n");
411 return E_INVALIDARG;
414 nsAString_InitDepend(&method_str, v);
415 nsres = nsIDOMHTMLFormElement_SetMethod(This->nsform, &method_str);
416 nsAString_Finish(&method_str);
417 if(NS_FAILED(nsres))
418 return E_FAIL;
420 return S_OK;
423 static HRESULT WINAPI HTMLFormElement_get_method(IHTMLFormElement *iface, BSTR *p)
425 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
426 nsAString method_str;
427 nsresult nsres;
429 TRACE("(%p)->(%p)\n", This, p);
431 nsAString_Init(&method_str, NULL);
432 nsres = nsIDOMHTMLFormElement_GetMethod(This->nsform, &method_str);
433 return return_nsstr(nsres, &method_str, p);
436 static HRESULT WINAPI HTMLFormElement_get_elements(IHTMLFormElement *iface, IDispatch **p)
438 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
439 nsIDOMHTMLCollection *elements;
440 nsresult nsres;
442 TRACE("(%p)->(%p)\n", This, p);
444 if(dispex_compat_mode(&This->element.node.event_target.dispex) < COMPAT_MODE_IE9) {
445 IDispatch_AddRef(*p = (IDispatch*)&This->IHTMLFormElement_iface);
446 return S_OK;
449 nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
450 if(NS_FAILED(nsres)) {
451 ERR("GetElements failed: %08lx\n", nsres);
452 return E_FAIL;
455 *p = (IDispatch*)create_collection_from_htmlcol(elements, dispex_compat_mode(&This->element.node.event_target.dispex));
456 nsIDOMHTMLCollection_Release(elements);
457 return S_OK;
460 static HRESULT WINAPI HTMLFormElement_put_target(IHTMLFormElement *iface, BSTR v)
462 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
463 nsAString str;
464 nsresult nsres;
466 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
468 nsAString_InitDepend(&str, v);
470 nsres = nsIDOMHTMLFormElement_SetTarget(This->nsform, &str);
472 nsAString_Finish(&str);
473 if (NS_FAILED(nsres)) {
474 ERR("Set Target(%s) failed: %08lx\n", wine_dbgstr_w(v), nsres);
475 return E_FAIL;
478 return S_OK;
481 static HRESULT WINAPI HTMLFormElement_get_target(IHTMLFormElement *iface, BSTR *p)
483 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
484 nsAString str;
485 nsresult nsres;
487 TRACE("(%p)->(%p)\n", This, p);
489 nsAString_Init(&str, NULL);
490 nsres = nsIDOMHTMLFormElement_GetTarget(This->nsform, &str);
492 return return_nsstr(nsres, &str, p);
495 static HRESULT WINAPI HTMLFormElement_put_name(IHTMLFormElement *iface, BSTR v)
497 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
498 nsAString name_str;
499 nsresult nsres;
501 TRACE("(%p)->(%s)\n", This, wine_dbgstr_w(v));
503 nsAString_InitDepend(&name_str, v);
504 nsres = nsIDOMHTMLFormElement_SetName(This->nsform, &name_str);
505 nsAString_Finish(&name_str);
506 if(NS_FAILED(nsres))
507 return E_FAIL;
509 return S_OK;
512 static HRESULT WINAPI HTMLFormElement_get_name(IHTMLFormElement *iface, BSTR *p)
514 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
515 nsAString name_str;
516 nsresult nsres;
518 TRACE("(%p)->(%p)\n", This, p);
520 nsAString_Init(&name_str, NULL);
521 nsres = nsIDOMHTMLFormElement_GetName(This->nsform, &name_str);
522 return return_nsstr(nsres, &name_str, p);
525 static HRESULT WINAPI HTMLFormElement_put_onsubmit(IHTMLFormElement *iface, VARIANT v)
527 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
529 TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
531 return set_node_event(&This->element.node, EVENTID_SUBMIT, &v);
534 static HRESULT WINAPI HTMLFormElement_get_onsubmit(IHTMLFormElement *iface, VARIANT *p)
536 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
538 TRACE("(%p)->(%p)\n", This, p);
540 return get_node_event(&This->element.node, EVENTID_SUBMIT, p);
543 static HRESULT WINAPI HTMLFormElement_put_onreset(IHTMLFormElement *iface, VARIANT v)
545 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
546 FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
547 return E_NOTIMPL;
550 static HRESULT WINAPI HTMLFormElement_get_onreset(IHTMLFormElement *iface, VARIANT *p)
552 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
553 FIXME("(%p)->(%p)\n", This, p);
554 return E_NOTIMPL;
557 static HRESULT WINAPI HTMLFormElement_submit(IHTMLFormElement *iface)
559 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
560 HTMLOuterWindow *window = NULL, *this_window = NULL;
561 nsAString action_uri_str, target_str, method_str;
562 nsIInputStream *post_stream;
563 BOOL is_post_submit = FALSE;
564 IUri *uri;
565 nsresult nsres;
566 HRESULT hres;
567 BOOL use_new_window = FALSE;
569 TRACE("(%p)\n", This);
571 if(This->element.node.doc) {
572 HTMLDocumentNode *doc = This->element.node.doc;
573 if(doc->window && doc->window->base.outer_window)
574 this_window = doc->window->base.outer_window;
576 if(!this_window) {
577 TRACE("No outer window\n");
578 return S_OK;
581 nsAString_Init(&target_str, NULL);
582 nsres = nsIDOMHTMLFormElement_GetTarget(This->nsform, &target_str);
583 if(NS_SUCCEEDED(nsres))
584 window = get_target_window(this_window, &target_str, &use_new_window);
586 if(!window && !use_new_window) {
587 nsAString_Finish(&target_str);
588 return S_OK;
591 nsAString_Init(&method_str, NULL);
592 nsres = nsIDOMHTMLFormElement_GetMethod(This->nsform, &method_str);
593 if(NS_SUCCEEDED(nsres)) {
594 const PRUnichar *method;
596 nsAString_GetData(&method_str, &method);
597 TRACE("method is %s\n", debugstr_w(method));
598 is_post_submit = !wcsicmp(method, L"post");
600 nsAString_Finish(&method_str);
603 * FIXME: We currently use our submit implementation for POST submit. We should always use it.
605 if(window && !is_post_submit) {
606 nsres = nsIDOMHTMLFormElement_Submit(This->nsform);
607 nsAString_Finish(&target_str);
608 IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
609 if(NS_FAILED(nsres)) {
610 ERR("Submit failed: %08lx\n", nsres);
611 return E_FAIL;
614 return S_OK;
617 nsAString_Init(&action_uri_str, NULL);
618 nsres = nsIDOMHTMLFormElement_GetFormData(This->nsform, NULL, &action_uri_str, &post_stream);
619 if(NS_SUCCEEDED(nsres)) {
620 const PRUnichar *action_uri;
622 nsAString_GetData(&action_uri_str, &action_uri);
623 hres = create_uri(action_uri, 0, &uri);
624 }else {
625 ERR("GetFormData failed: %08lx\n", nsres);
626 hres = E_FAIL;
628 nsAString_Finish(&action_uri_str);
629 if(SUCCEEDED(hres)) {
630 const PRUnichar *target;
632 nsAString_GetData(&target_str, &target);
633 hres = submit_form(window, target, uri, post_stream);
634 IUri_Release(uri);
637 nsAString_Finish(&target_str);
638 if(window)
639 IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
640 if(post_stream)
641 nsIInputStream_Release(post_stream);
642 return hres;
645 static HRESULT WINAPI HTMLFormElement_reset(IHTMLFormElement *iface)
647 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
648 nsresult nsres;
650 TRACE("(%p)->()\n", This);
651 nsres = nsIDOMHTMLFormElement_Reset(This->nsform);
652 if (NS_FAILED(nsres)) {
653 ERR("Reset failed: %08lx\n", nsres);
654 return E_FAIL;
657 return S_OK;
660 static HRESULT WINAPI HTMLFormElement_put_length(IHTMLFormElement *iface, LONG v)
662 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
663 FIXME("(%p)->(%ld)\n", This, v);
664 return E_NOTIMPL;
667 static HRESULT WINAPI HTMLFormElement_get_length(IHTMLFormElement *iface, LONG *p)
669 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
670 nsresult nsres;
672 TRACE("(%p)->(%p)\n", This, p);
674 nsres = nsIDOMHTMLFormElement_GetLength(This->nsform, p);
675 if(NS_FAILED(nsres)) {
676 ERR("GetLength failed: %08lx\n", nsres);
677 return E_FAIL;
680 return S_OK;
683 static HRESULT WINAPI HTMLFormElement__newEnum(IHTMLFormElement *iface, IUnknown **p)
685 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
686 HTMLFormElementEnum *ret;
688 TRACE("(%p)->(%p)\n", This, p);
690 ret = heap_alloc(sizeof(*ret));
691 if(!ret)
692 return E_OUTOFMEMORY;
694 ret->IEnumVARIANT_iface.lpVtbl = &HTMLFormElementEnumVtbl;
695 ret->ref = 1;
696 ret->iter = 0;
698 HTMLFormElement_AddRef(&This->IHTMLFormElement_iface);
699 ret->elem = This;
701 *p = (IUnknown*)&ret->IEnumVARIANT_iface;
702 return S_OK;
705 static HRESULT WINAPI HTMLFormElement_item(IHTMLFormElement *iface, VARIANT name,
706 VARIANT index, IDispatch **pdisp)
708 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
710 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
712 if(!pdisp)
713 return E_INVALIDARG;
714 *pdisp = NULL;
716 if(V_VT(&name) == VT_I4) {
717 if(V_I4(&name) < 0) {
718 *pdisp = NULL;
719 return dispex_compat_mode(&This->element.node.event_target.dispex) >= COMPAT_MODE_IE9
720 ? S_OK : E_INVALIDARG;
722 return htmlform_item(This, V_I4(&name), pdisp);
725 FIXME("Unsupported args\n");
726 return E_NOTIMPL;
729 static HRESULT WINAPI HTMLFormElement_tags(IHTMLFormElement *iface, VARIANT tagName,
730 IDispatch **pdisp)
732 HTMLFormElement *This = impl_from_IHTMLFormElement(iface);
733 FIXME("(%p)->(v %p)\n", This, pdisp);
734 return E_NOTIMPL;
737 static const IHTMLFormElementVtbl HTMLFormElementVtbl = {
738 HTMLFormElement_QueryInterface,
739 HTMLFormElement_AddRef,
740 HTMLFormElement_Release,
741 HTMLFormElement_GetTypeInfoCount,
742 HTMLFormElement_GetTypeInfo,
743 HTMLFormElement_GetIDsOfNames,
744 HTMLFormElement_Invoke,
745 HTMLFormElement_put_action,
746 HTMLFormElement_get_action,
747 HTMLFormElement_put_dir,
748 HTMLFormElement_get_dir,
749 HTMLFormElement_put_encoding,
750 HTMLFormElement_get_encoding,
751 HTMLFormElement_put_method,
752 HTMLFormElement_get_method,
753 HTMLFormElement_get_elements,
754 HTMLFormElement_put_target,
755 HTMLFormElement_get_target,
756 HTMLFormElement_put_name,
757 HTMLFormElement_get_name,
758 HTMLFormElement_put_onsubmit,
759 HTMLFormElement_get_onsubmit,
760 HTMLFormElement_put_onreset,
761 HTMLFormElement_get_onreset,
762 HTMLFormElement_submit,
763 HTMLFormElement_reset,
764 HTMLFormElement_put_length,
765 HTMLFormElement_get_length,
766 HTMLFormElement__newEnum,
767 HTMLFormElement_item,
768 HTMLFormElement_tags
771 static inline HTMLFormElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface)
773 return CONTAINING_RECORD(iface, HTMLFormElement, element.node);
776 static HRESULT HTMLFormElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
778 HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
780 *ppv = NULL;
782 if(IsEqualGUID(&IID_IUnknown, riid)) {
783 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
784 *ppv = &This->IHTMLFormElement_iface;
785 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
786 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
787 *ppv = &This->IHTMLFormElement_iface;
788 }else if(IsEqualGUID(&IID_IHTMLFormElement, riid)) {
789 TRACE("(%p)->(IID_IHTMLFormElement %p)\n", This, ppv);
790 *ppv = &This->IHTMLFormElement_iface;
791 }else if(IsEqualGUID(&DIID_DispHTMLFormElement, riid)) {
792 TRACE("(%p)->(DIID_DispHTMLFormElement %p)\n", This, ppv);
793 *ppv = &This->IHTMLFormElement_iface;
796 if(*ppv) {
797 IUnknown_AddRef((IUnknown*)*ppv);
798 return S_OK;
801 return HTMLElement_QI(&This->element.node, riid, ppv);
804 static HRESULT HTMLFormElement_get_dispid(HTMLDOMNode *iface,
805 BSTR name, DWORD grfdex, DISPID *pid)
807 HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
808 nsIDOMHTMLCollection *elements;
809 nsAString nsstr, name_str;
810 UINT32 len, i;
811 nsresult nsres;
812 HRESULT hres = DISP_E_UNKNOWNNAME;
814 TRACE("(%p)->(%s %lx %p)\n", This, wine_dbgstr_w(name), grfdex, pid);
816 nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
817 if(NS_FAILED(nsres)) {
818 FIXME("GetElements failed: 0x%08lx\n", nsres);
819 return E_FAIL;
822 nsres = nsIDOMHTMLCollection_GetLength(elements, &len);
823 if(NS_FAILED(nsres)) {
824 FIXME("GetLength failed: 0x%08lx\n", nsres);
825 nsIDOMHTMLCollection_Release(elements);
826 return E_FAIL;
829 if(len > MSHTML_CUSTOM_DISPID_CNT)
830 len = MSHTML_CUSTOM_DISPID_CNT;
832 /* FIXME: Implement in more generic way */
833 if('0' <= *name && *name <= '9') {
834 WCHAR *end_ptr;
836 i = wcstoul(name, &end_ptr, 10);
837 if(!*end_ptr && i < len) {
838 *pid = MSHTML_DISPID_CUSTOM_MIN + i;
839 return S_OK;
843 nsAString_Init(&nsstr, NULL);
844 for(i = 0; i < len; ++i) {
845 nsIDOMNode *nsitem;
846 nsIDOMElement *elem;
847 const PRUnichar *str;
849 nsres = nsIDOMHTMLCollection_Item(elements, i, &nsitem);
850 if(NS_FAILED(nsres)) {
851 FIXME("Item failed: 0x%08lx\n", nsres);
852 hres = E_FAIL;
853 break;
856 nsres = nsIDOMNode_QueryInterface(nsitem, &IID_nsIDOMElement, (void**)&elem);
857 nsIDOMNode_Release(nsitem);
858 if(NS_FAILED(nsres)) {
859 FIXME("Failed to get nsIDOMHTMLNode interface: 0x%08lx\n", nsres);
860 hres = E_FAIL;
861 break;
864 /* compare by id attr */
865 nsres = nsIDOMElement_GetId(elem, &nsstr);
866 if(NS_FAILED(nsres)) {
867 FIXME("GetId failed: 0x%08lx\n", nsres);
868 nsIDOMElement_Release(elem);
869 hres = E_FAIL;
870 break;
872 nsAString_GetData(&nsstr, &str);
873 if(!wcsicmp(str, name)) {
874 nsIDOMElement_Release(elem);
875 /* FIXME: using index for dispid */
876 *pid = MSHTML_DISPID_CUSTOM_MIN + i;
877 hres = S_OK;
878 break;
881 /* compare by name attr */
882 nsres = get_elem_attr_value(elem, L"name", &name_str, &str);
883 nsIDOMElement_Release(elem);
884 if(NS_SUCCEEDED(nsres)) {
885 if(!wcsicmp(str, name)) {
886 nsAString_Finish(&name_str);
887 /* FIXME: using index for dispid */
888 *pid = MSHTML_DISPID_CUSTOM_MIN + i;
889 hres = S_OK;
890 break;
892 nsAString_Finish(&name_str);
896 nsAString_Finish(&nsstr);
897 nsIDOMHTMLCollection_Release(elements);
898 return hres;
901 static HRESULT HTMLFormElement_dispex_get_name(HTMLDOMNode *iface, DISPID id, BSTR *name)
903 HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
904 DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN;
905 nsIDOMHTMLCollection *elements;
906 nsresult nsres;
907 UINT32 len = 0;
908 WCHAR buf[11];
910 nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
911 if(NS_FAILED(nsres))
912 return map_nsresult(nsres);
914 nsres = nsIDOMHTMLCollection_GetLength(elements, &len);
915 nsIDOMHTMLCollection_Release(elements);
916 if(NS_FAILED(nsres))
917 return map_nsresult(nsres);
919 if(idx >= len)
920 return DISP_E_MEMBERNOTFOUND;
922 len = swprintf(buf, ARRAY_SIZE(buf), L"%u", idx);
923 return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY;
926 static HRESULT HTMLFormElement_invoke(HTMLDOMNode *iface,
927 DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res,
928 EXCEPINFO *ei, IServiceProvider *caller)
930 HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
931 IDispatch *ret;
932 HRESULT hres;
934 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
936 hres = htmlform_item(This, id - MSHTML_DISPID_CUSTOM_MIN, &ret);
937 if(FAILED(hres))
938 return hres;
940 if(ret) {
941 V_VT(res) = VT_DISPATCH;
942 V_DISPATCH(res) = ret;
943 }else {
944 V_VT(res) = VT_NULL;
946 return S_OK;
949 static HRESULT HTMLFormElement_handle_event(HTMLDOMNode *iface, DWORD eid, nsIDOMEvent *event, BOOL *prevent_default)
951 HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
953 if(eid == EVENTID_SUBMIT) {
954 *prevent_default = TRUE;
955 return IHTMLFormElement_submit(&This->IHTMLFormElement_iface);
958 return HTMLElement_handle_event(&This->element.node, eid, event, prevent_default);
961 static void HTMLFormElement_traverse(HTMLDOMNode *iface, nsCycleCollectionTraversalCallback *cb)
963 HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
965 if(This->nsform)
966 note_cc_edge((nsISupports*)This->nsform, "This->nsform", cb);
969 static void HTMLFormElement_unlink(HTMLDOMNode *iface)
971 HTMLFormElement *This = impl_from_HTMLDOMNode(iface);
973 if(This->nsform) {
974 nsIDOMHTMLFormElement *nsform = This->nsform;
976 This->nsform = NULL;
977 nsIDOMHTMLFormElement_Release(nsform);
981 static const NodeImplVtbl HTMLFormElementImplVtbl = {
982 &CLSID_HTMLFormElement,
983 HTMLFormElement_QI,
984 HTMLElement_destructor,
985 HTMLElement_cpc,
986 HTMLElement_clone,
987 HTMLFormElement_handle_event,
988 HTMLElement_get_attr_col,
989 NULL,
990 NULL,
991 NULL,
992 NULL,
993 NULL,
994 HTMLFormElement_get_dispid,
995 HTMLFormElement_dispex_get_name,
996 HTMLFormElement_invoke,
997 NULL,
998 HTMLFormElement_traverse,
999 HTMLFormElement_unlink
1002 static const tid_t HTMLFormElement_iface_tids[] = {
1003 HTMLELEMENT_TIDS,
1004 IHTMLFormElement_tid,
1008 static dispex_static_data_t HTMLFormElement_dispex = {
1009 L"HTMLFormElement",
1010 NULL,
1011 DispHTMLFormElement_tid,
1012 HTMLFormElement_iface_tids,
1013 HTMLElement_init_dispex_info
1016 HRESULT HTMLFormElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem)
1018 HTMLFormElement *ret;
1019 nsresult nsres;
1021 ret = heap_alloc_zero(sizeof(HTMLFormElement));
1022 if(!ret)
1023 return E_OUTOFMEMORY;
1025 ret->IHTMLFormElement_iface.lpVtbl = &HTMLFormElementVtbl;
1026 ret->element.node.vtbl = &HTMLFormElementImplVtbl;
1028 HTMLElement_Init(&ret->element, doc, nselem, &HTMLFormElement_dispex);
1030 nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMHTMLFormElement, (void**)&ret->nsform);
1031 assert(nsres == NS_OK);
1033 *elem = &ret->element;
1034 return S_OK;