gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / mshtml / htmlform.c
blob61bf686865f5eefa226017ab01cb949f8ed7a964
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 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 = malloc(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_DispatchEx(DispatchEx *iface)
773 return CONTAINING_RECORD(iface, HTMLFormElement, element.node.event_target.dispex);
776 static void *HTMLFormElement_query_interface(DispatchEx *dispex, REFIID riid)
778 HTMLFormElement *This = impl_from_DispatchEx(dispex);
780 if(IsEqualGUID(&IID_IHTMLFormElement, riid))
781 return &This->IHTMLFormElement_iface;
782 if(IsEqualGUID(&DIID_DispHTMLFormElement, riid))
783 return &This->IHTMLFormElement_iface;
785 return HTMLElement_query_interface(&This->element.node.event_target.dispex, riid);
788 static void HTMLFormElement_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCallback *cb)
790 HTMLFormElement *This = impl_from_DispatchEx(dispex);
791 HTMLDOMNode_traverse(dispex, cb);
793 if(This->nsform)
794 note_cc_edge((nsISupports*)This->nsform, "nsform", cb);
797 static void HTMLFormElement_unlink(DispatchEx *dispex)
799 HTMLFormElement *This = impl_from_DispatchEx(dispex);
800 HTMLDOMNode_unlink(dispex);
801 unlink_ref(&This->nsform);
804 static HRESULT HTMLFormElement_get_dispid(DispatchEx *dispex, BSTR name, DWORD grfdex, DISPID *dispid)
806 HTMLFormElement *This = impl_from_DispatchEx(dispex);
807 nsIDOMHTMLCollection *elements;
808 nsAString nsstr, name_str;
809 UINT32 len, i;
810 nsresult nsres;
811 HRESULT hres = DISP_E_UNKNOWNNAME;
813 TRACE("(%p)->(%s %lx %p)\n", This, wine_dbgstr_w(name), grfdex, dispid);
815 nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
816 if(NS_FAILED(nsres)) {
817 FIXME("GetElements failed: 0x%08lx\n", nsres);
818 return E_FAIL;
821 nsres = nsIDOMHTMLCollection_GetLength(elements, &len);
822 if(NS_FAILED(nsres)) {
823 FIXME("GetLength failed: 0x%08lx\n", nsres);
824 nsIDOMHTMLCollection_Release(elements);
825 return E_FAIL;
828 if(len > MSHTML_CUSTOM_DISPID_CNT)
829 len = MSHTML_CUSTOM_DISPID_CNT;
831 /* FIXME: Implement in more generic way */
832 if('0' <= *name && *name <= '9') {
833 WCHAR *end_ptr;
835 i = wcstoul(name, &end_ptr, 10);
836 if(!*end_ptr && i < len) {
837 *dispid = MSHTML_DISPID_CUSTOM_MIN + i;
838 return S_OK;
842 nsAString_Init(&nsstr, NULL);
843 for(i = 0; i < len; ++i) {
844 nsIDOMNode *nsitem;
845 nsIDOMElement *elem;
846 const PRUnichar *str;
848 nsres = nsIDOMHTMLCollection_Item(elements, i, &nsitem);
849 if(NS_FAILED(nsres)) {
850 FIXME("Item failed: 0x%08lx\n", nsres);
851 hres = E_FAIL;
852 break;
855 nsres = nsIDOMNode_QueryInterface(nsitem, &IID_nsIDOMElement, (void**)&elem);
856 nsIDOMNode_Release(nsitem);
857 if(NS_FAILED(nsres)) {
858 FIXME("Failed to get nsIDOMHTMLNode interface: 0x%08lx\n", nsres);
859 hres = E_FAIL;
860 break;
863 /* compare by id attr */
864 nsres = nsIDOMElement_GetId(elem, &nsstr);
865 if(NS_FAILED(nsres)) {
866 FIXME("GetId failed: 0x%08lx\n", nsres);
867 nsIDOMElement_Release(elem);
868 hres = E_FAIL;
869 break;
871 nsAString_GetData(&nsstr, &str);
872 if(!wcsicmp(str, name)) {
873 nsIDOMElement_Release(elem);
874 /* FIXME: using index for dispid */
875 *dispid = MSHTML_DISPID_CUSTOM_MIN + i;
876 hres = S_OK;
877 break;
880 /* compare by name attr */
881 nsres = get_elem_attr_value(elem, L"name", &name_str, &str);
882 nsIDOMElement_Release(elem);
883 if(NS_SUCCEEDED(nsres)) {
884 if(!wcsicmp(str, name)) {
885 nsAString_Finish(&name_str);
886 /* FIXME: using index for dispid */
887 *dispid = MSHTML_DISPID_CUSTOM_MIN + i;
888 hres = S_OK;
889 break;
891 nsAString_Finish(&name_str);
895 nsAString_Finish(&nsstr);
896 nsIDOMHTMLCollection_Release(elements);
897 return hres;
900 static HRESULT HTMLFormElement_dispex_get_name(DispatchEx *dispex, DISPID id, BSTR *name)
902 HTMLFormElement *This = impl_from_DispatchEx(dispex);
903 DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN;
904 nsIDOMHTMLCollection *elements;
905 nsresult nsres;
906 UINT32 len = 0;
907 WCHAR buf[11];
909 nsres = nsIDOMHTMLFormElement_GetElements(This->nsform, &elements);
910 if(NS_FAILED(nsres))
911 return map_nsresult(nsres);
913 nsres = nsIDOMHTMLCollection_GetLength(elements, &len);
914 nsIDOMHTMLCollection_Release(elements);
915 if(NS_FAILED(nsres))
916 return map_nsresult(nsres);
918 if(idx >= len)
919 return DISP_E_MEMBERNOTFOUND;
921 len = swprintf(buf, ARRAY_SIZE(buf), L"%u", idx);
922 return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY;
925 static HRESULT HTMLFormElement_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
926 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
928 HTMLFormElement *This = impl_from_DispatchEx(dispex);
929 IDispatch *ret;
930 HRESULT hres;
932 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
934 hres = htmlform_item(This, id - MSHTML_DISPID_CUSTOM_MIN, &ret);
935 if(FAILED(hres))
936 return hres;
938 if(ret) {
939 V_VT(res) = VT_DISPATCH;
940 V_DISPATCH(res) = ret;
941 }else {
942 V_VT(res) = VT_NULL;
944 return S_OK;
947 static HRESULT HTMLFormElement_handle_event(DispatchEx *dispex, eventid_t eid, nsIDOMEvent *event, BOOL *prevent_default)
949 HTMLFormElement *This = impl_from_DispatchEx(dispex);
951 if(eid == EVENTID_SUBMIT) {
952 *prevent_default = TRUE;
953 return IHTMLFormElement_submit(&This->IHTMLFormElement_iface);
956 return HTMLElement_handle_event(&This->element.node.event_target.dispex, eid, event, prevent_default);
959 static const NodeImplVtbl HTMLFormElementImplVtbl = {
960 .clsid = &CLSID_HTMLFormElement,
961 .cpc_entries = HTMLElement_cpc,
962 .clone = HTMLElement_clone,
963 .get_attr_col = HTMLElement_get_attr_col,
966 static const event_target_vtbl_t HTMLFormElement_event_target_vtbl = {
968 HTMLELEMENT_DISPEX_VTBL_ENTRIES,
969 .query_interface= HTMLFormElement_query_interface,
970 .destructor = HTMLElement_destructor,
971 .traverse = HTMLFormElement_traverse,
972 .unlink = HTMLFormElement_unlink,
973 .get_dispid = HTMLFormElement_get_dispid,
974 .get_name = HTMLFormElement_dispex_get_name,
975 .invoke = HTMLFormElement_invoke
977 HTMLELEMENT_EVENT_TARGET_VTBL_ENTRIES,
978 .handle_event = HTMLFormElement_handle_event
981 static const tid_t HTMLFormElement_iface_tids[] = {
982 HTMLELEMENT_TIDS,
983 IHTMLFormElement_tid,
987 static dispex_static_data_t HTMLFormElement_dispex = {
988 "HTMLFormElement",
989 &HTMLFormElement_event_target_vtbl.dispex_vtbl,
990 DispHTMLFormElement_tid,
991 HTMLFormElement_iface_tids,
992 HTMLElement_init_dispex_info
995 HRESULT HTMLFormElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem)
997 HTMLFormElement *ret;
998 nsresult nsres;
1000 ret = calloc(1, sizeof(HTMLFormElement));
1001 if(!ret)
1002 return E_OUTOFMEMORY;
1004 ret->IHTMLFormElement_iface.lpVtbl = &HTMLFormElementVtbl;
1005 ret->element.node.vtbl = &HTMLFormElementImplVtbl;
1007 HTMLElement_Init(&ret->element, doc, nselem, &HTMLFormElement_dispex);
1009 nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMHTMLFormElement, (void**)&ret->nsform);
1010 assert(nsres == NS_OK);
1012 *elem = &ret->element;
1013 return S_OK;