mshtml: Added possibility for node implementations to add default event handlers.
[wine] / dlls / mshtml / htmlselect.c
1 /*
2  * Copyright 2006 Jacek Caban 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 typedef struct {
36     HTMLElement element;
37
38     IHTMLSelectElement IHTMLSelectElement_iface;
39
40     nsIDOMHTMLSelectElement *nsselect;
41 } HTMLSelectElement;
42
43 static inline HTMLSelectElement *impl_from_IHTMLSelectElement(IHTMLSelectElement *iface)
44 {
45     return CONTAINING_RECORD(iface, HTMLSelectElement, IHTMLSelectElement_iface);
46 }
47
48 static HRESULT htmlselect_item(HTMLSelectElement *This, int i, IDispatch **ret)
49 {
50     nsIDOMHTMLOptionsCollection *nscol;
51     nsIDOMNode *nsnode;
52     nsresult nsres;
53     HRESULT hres;
54
55     nsres = nsIDOMHTMLSelectElement_GetOptions(This->nsselect, &nscol);
56     if(NS_FAILED(nsres)) {
57         ERR("GetOptions failed: %08x\n", nsres);
58         return E_FAIL;
59     }
60
61     nsres = nsIDOMHTMLOptionsCollection_Item(nscol, i, &nsnode);
62     nsIDOMHTMLOptionsCollection_Release(nscol);
63     if(NS_FAILED(nsres)) {
64         ERR("Item failed: %08x\n", nsres);
65         return E_FAIL;
66     }
67
68     if(nsnode) {
69         HTMLDOMNode *node;
70
71         hres = get_node(This->element.node.doc, nsnode, TRUE, &node);
72         nsIDOMNode_Release(nsnode);
73         if(FAILED(hres))
74             return hres;
75
76         IHTMLDOMNode_AddRef(&node->IHTMLDOMNode_iface);
77         *ret = (IDispatch*)&node->IHTMLDOMNode_iface;
78     }else {
79         *ret = NULL;
80     }
81     return S_OK;
82 }
83
84 static HRESULT WINAPI HTMLSelectElement_QueryInterface(IHTMLSelectElement *iface,
85                                                          REFIID riid, void **ppv)
86 {
87     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
88
89     return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv);
90 }
91
92 static ULONG WINAPI HTMLSelectElement_AddRef(IHTMLSelectElement *iface)
93 {
94     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
95
96     return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface);
97 }
98
99 static ULONG WINAPI HTMLSelectElement_Release(IHTMLSelectElement *iface)
100 {
101     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
102
103     return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface);
104 }
105
106 static HRESULT WINAPI HTMLSelectElement_GetTypeInfoCount(IHTMLSelectElement *iface, UINT *pctinfo)
107 {
108     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
109
110     return IDispatchEx_GetTypeInfoCount(&This->element.node.dispex.IDispatchEx_iface, pctinfo);
111 }
112
113 static HRESULT WINAPI HTMLSelectElement_GetTypeInfo(IHTMLSelectElement *iface, UINT iTInfo,
114                                               LCID lcid, ITypeInfo **ppTInfo)
115 {
116     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
117
118     return IDispatchEx_GetTypeInfo(&This->element.node.dispex.IDispatchEx_iface, iTInfo, lcid,
119             ppTInfo);
120 }
121
122 static HRESULT WINAPI HTMLSelectElement_GetIDsOfNames(IHTMLSelectElement *iface, REFIID riid,
123                                                 LPOLESTR *rgszNames, UINT cNames,
124                                                 LCID lcid, DISPID *rgDispId)
125 {
126     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
127
128     return IDispatchEx_GetIDsOfNames(&This->element.node.dispex.IDispatchEx_iface, riid, rgszNames,
129             cNames, lcid, rgDispId);
130 }
131
132 static HRESULT WINAPI HTMLSelectElement_Invoke(IHTMLSelectElement *iface, DISPID dispIdMember,
133                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
134                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
135 {
136     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
137
138     return IDispatchEx_Invoke(&This->element.node.dispex.IDispatchEx_iface, dispIdMember, riid,
139             lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
140 }
141
142 static HRESULT WINAPI HTMLSelectElement_put_size(IHTMLSelectElement *iface, LONG v)
143 {
144     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
145     FIXME("(%p)->(%d)\n", This, v);
146     return E_NOTIMPL;
147 }
148
149 static HRESULT WINAPI HTMLSelectElement_get_size(IHTMLSelectElement *iface, LONG *p)
150 {
151     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
152     FIXME("(%p)->(%p)\n", This, p);
153     return E_NOTIMPL;
154 }
155
156 static HRESULT WINAPI HTMLSelectElement_put_multiple(IHTMLSelectElement *iface, VARIANT_BOOL v)
157 {
158     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
159     FIXME("(%p)->(%x)\n", This, v);
160     return E_NOTIMPL;
161 }
162
163 static HRESULT WINAPI HTMLSelectElement_get_multiple(IHTMLSelectElement *iface, VARIANT_BOOL *p)
164 {
165     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
166     FIXME("(%p)->(%p)\n", This, p);
167     return E_NOTIMPL;
168 }
169
170 static HRESULT WINAPI HTMLSelectElement_put_name(IHTMLSelectElement *iface, BSTR v)
171 {
172     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
173     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
174     return E_NOTIMPL;
175 }
176
177 static HRESULT WINAPI HTMLSelectElement_get_name(IHTMLSelectElement *iface, BSTR *p)
178 {
179     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
180     nsAString name_str;
181     const PRUnichar *name = NULL;
182     nsresult nsres;
183
184     TRACE("(%p)->(%p)\n", This, p);
185
186     nsAString_Init(&name_str, NULL);
187
188     nsres = nsIDOMHTMLSelectElement_GetName(This->nsselect, &name_str);
189     if(NS_SUCCEEDED(nsres)) {
190         static const WCHAR wszGarbage[] = {'g','a','r','b','a','g','e',0};
191
192         nsAString_GetData(&name_str, &name);
193
194         /*
195          * Native never returns empty string here. If an element has no name,
196          * name of previous element or ramdom data is returned.
197          */
198         *p = SysAllocString(*name ? name : wszGarbage);
199     }else {
200         ERR("GetName failed: %08x\n", nsres);
201     }
202
203     nsAString_Finish(&name_str);
204
205     TRACE("name=%s\n", debugstr_w(*p));
206     return S_OK;
207 }
208
209 static HRESULT WINAPI HTMLSelectElement_get_options(IHTMLSelectElement *iface, IDispatch **p)
210 {
211     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
212
213     TRACE("(%p)->(%p)\n", This, p);
214
215     *p = (IDispatch*)&This->IHTMLSelectElement_iface;
216     IDispatch_AddRef(*p);
217     return S_OK;
218 }
219
220 static HRESULT WINAPI HTMLSelectElement_put_onchange(IHTMLSelectElement *iface, VARIANT v)
221 {
222     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
223
224     TRACE("(%p)->()\n", This);
225
226     return set_node_event(&This->element.node, EVENTID_CHANGE, &v);
227 }
228
229 static HRESULT WINAPI HTMLSelectElement_get_onchange(IHTMLSelectElement *iface, VARIANT *p)
230 {
231     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
232     FIXME("(%p)->(%p)\n", This, p);
233     return E_NOTIMPL;
234 }
235
236 static HRESULT WINAPI HTMLSelectElement_put_selectedIndex(IHTMLSelectElement *iface, LONG v)
237 {
238     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
239     nsresult nsres;
240
241     TRACE("(%p)->(%d)\n", This, v);
242
243     nsres = nsIDOMHTMLSelectElement_SetSelectedIndex(This->nsselect, v);
244     if(NS_FAILED(nsres))
245         ERR("SetSelectedIndex failed: %08x\n", nsres);
246
247     return S_OK;
248 }
249
250 static HRESULT WINAPI HTMLSelectElement_get_selectedIndex(IHTMLSelectElement *iface, LONG *p)
251 {
252     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
253     PRInt32 idx = 0;
254     nsresult nsres;
255
256     TRACE("(%p)->(%p)\n", This, p);
257
258     nsres = nsIDOMHTMLSelectElement_GetSelectedIndex(This->nsselect, &idx);
259     if(NS_FAILED(nsres))
260         ERR("GetSelectedIndex failed: %08x\n", nsres);
261
262     *p = idx;
263     return S_OK;
264 }
265
266 static HRESULT WINAPI HTMLSelectElement_get_type(IHTMLSelectElement *iface, BSTR *p)
267 {
268     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
269     const PRUnichar *type;
270     nsAString type_str;
271     nsresult nsres;
272     HRESULT hres = S_OK;
273
274     TRACE("(%p)->(%p)\n", This, p);
275
276     nsAString_Init(&type_str, NULL);
277     nsres = nsIDOMHTMLSelectElement_GetType(This->nsselect, &type_str);
278     if(NS_SUCCEEDED(nsres)) {
279         nsAString_GetData(&type_str, &type);
280         *p = *type ? SysAllocString(type) : NULL;
281     }else {
282         ERR("GetType failed: %08x\n", nsres);
283         hres = E_FAIL;
284     }
285
286     nsAString_Finish(&type_str);
287
288     return hres;
289 }
290
291 static HRESULT WINAPI HTMLSelectElement_put_value(IHTMLSelectElement *iface, BSTR v)
292 {
293     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
294     nsAString value_str;
295     nsresult nsres;
296
297     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
298
299     nsAString_InitDepend(&value_str, v);
300     nsres = nsIDOMHTMLSelectElement_SetValue(This->nsselect, &value_str);
301     nsAString_Finish(&value_str);
302     if(NS_FAILED(nsres))
303         ERR("SetValue failed: %08x\n", nsres);
304
305     return S_OK;
306 }
307
308 static HRESULT WINAPI HTMLSelectElement_get_value(IHTMLSelectElement *iface, BSTR *p)
309 {
310     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
311     nsAString value_str;
312     const PRUnichar *value = NULL;
313     nsresult nsres;
314
315     TRACE("(%p)->(%p)\n", This, p);
316
317     nsAString_Init(&value_str, NULL);
318
319     nsres = nsIDOMHTMLSelectElement_GetValue(This->nsselect, &value_str);
320     if(NS_SUCCEEDED(nsres)) {
321         nsAString_GetData(&value_str, &value);
322         *p = *value ? SysAllocString(value) : NULL;
323     }else {
324         ERR("GetValue failed: %08x\n", nsres);
325     }
326
327     nsAString_Finish(&value_str);
328
329     TRACE("value=%s\n", debugstr_w(*p));
330     return S_OK;
331 }
332
333 static HRESULT WINAPI HTMLSelectElement_put_disabled(IHTMLSelectElement *iface, VARIANT_BOOL v)
334 {
335     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
336     nsresult nsres;
337
338     TRACE("(%p)->(%x)\n", This, v);
339
340     nsres = nsIDOMHTMLSelectElement_SetDisabled(This->nsselect, v != VARIANT_FALSE);
341     if(NS_FAILED(nsres)) {
342         ERR("SetDisabled failed: %08x\n", nsres);
343         return E_FAIL;
344     }
345
346     return S_OK;
347 }
348
349 static HRESULT WINAPI HTMLSelectElement_get_disabled(IHTMLSelectElement *iface, VARIANT_BOOL *p)
350 {
351     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
352     PRBool disabled = FALSE;
353     nsresult nsres;
354
355     TRACE("(%p)->(%p)\n", This, p);
356
357     nsres = nsIDOMHTMLSelectElement_GetDisabled(This->nsselect, &disabled);
358     if(NS_FAILED(nsres)) {
359         ERR("GetDisabled failed: %08x\n", nsres);
360         return E_FAIL;
361     }
362
363     *p = disabled ? VARIANT_TRUE : VARIANT_FALSE;
364     return S_OK;
365 }
366
367 static HRESULT WINAPI HTMLSelectElement_get_form(IHTMLSelectElement *iface, IHTMLFormElement **p)
368 {
369     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
370     FIXME("(%p)->(%p)\n", This, p);
371     return E_NOTIMPL;
372 }
373
374 static HRESULT WINAPI HTMLSelectElement_add(IHTMLSelectElement *iface, IHTMLElement *element,
375                                             VARIANT before)
376 {
377     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
378     IHTMLDOMNode *node, *tmp;
379     HRESULT hres;
380
381     FIXME("(%p)->(%p %s): semi-stub\n", This, element, debugstr_variant(&before));
382
383     if(V_VT(&before) != VT_EMPTY) {
384         FIXME("unhandled before %s\n", debugstr_variant(&before));
385         return E_NOTIMPL;
386     }
387
388     hres = IHTMLElement_QueryInterface(element, &IID_IHTMLDOMNode, (void**)&node);
389     if(FAILED(hres))
390         return hres;
391
392     hres = IHTMLDOMNode_appendChild(&This->element.node.IHTMLDOMNode_iface, node, &tmp);
393     IHTMLDOMNode_Release(node);
394     if(SUCCEEDED(hres) && tmp)
395         IHTMLDOMNode_Release(tmp);
396
397     return hres;
398 }
399
400 static HRESULT WINAPI HTMLSelectElement_remove(IHTMLSelectElement *iface, LONG index)
401 {
402     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
403     FIXME("(%p)->(%d)\n", This, index);
404     return E_NOTIMPL;
405 }
406
407 static HRESULT WINAPI HTMLSelectElement_put_length(IHTMLSelectElement *iface, LONG v)
408 {
409     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
410     nsresult nsres;
411
412     TRACE("(%p)->(%d)\n", This, v);
413
414     nsres = nsIDOMHTMLSelectElement_SetLength(This->nsselect, v);
415     if(NS_FAILED(nsres))
416         ERR("SetLength failed: %08x\n", nsres);
417
418     return S_OK;
419 }
420
421 static HRESULT WINAPI HTMLSelectElement_get_length(IHTMLSelectElement *iface, LONG *p)
422 {
423     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
424     PRUint32 length = 0;
425     nsresult nsres;
426
427     TRACE("(%p)->(%p)\n", This, p);
428
429     nsres = nsIDOMHTMLSelectElement_GetLength(This->nsselect, &length);
430     if(NS_FAILED(nsres))
431         ERR("GetLength failed: %08x\n", nsres);
432
433     *p = length;
434
435     TRACE("ret %d\n", *p);
436     return S_OK;
437 }
438
439 static HRESULT WINAPI HTMLSelectElement_get__newEnum(IHTMLSelectElement *iface, IUnknown **p)
440 {
441     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
442     FIXME("(%p)->(%p)\n", This, p);
443     return E_NOTIMPL;
444 }
445
446 static HRESULT WINAPI HTMLSelectElement_item(IHTMLSelectElement *iface, VARIANT name,
447                                              VARIANT index, IDispatch **pdisp)
448 {
449     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
450
451     TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&name), debugstr_variant(&index), pdisp);
452
453     if(!pdisp)
454         return E_POINTER;
455     *pdisp = NULL;
456
457     if(V_VT(&name) == VT_I4) {
458         if(V_I4(&name) < 0)
459             return E_INVALIDARG;
460         return htmlselect_item(This, V_I4(&name), pdisp);
461     }
462
463     FIXME("Unsupported args\n");
464     return E_NOTIMPL;
465 }
466
467 static HRESULT WINAPI HTMLSelectElement_tags(IHTMLSelectElement *iface, VARIANT tagName,
468                                              IDispatch **pdisp)
469 {
470     HTMLSelectElement *This = impl_from_IHTMLSelectElement(iface);
471     FIXME("(%p)->(v %p)\n", This, pdisp);
472     return E_NOTIMPL;
473 }
474
475 static const IHTMLSelectElementVtbl HTMLSelectElementVtbl = {
476     HTMLSelectElement_QueryInterface,
477     HTMLSelectElement_AddRef,
478     HTMLSelectElement_Release,
479     HTMLSelectElement_GetTypeInfoCount,
480     HTMLSelectElement_GetTypeInfo,
481     HTMLSelectElement_GetIDsOfNames,
482     HTMLSelectElement_Invoke,
483     HTMLSelectElement_put_size,
484     HTMLSelectElement_get_size,
485     HTMLSelectElement_put_multiple,
486     HTMLSelectElement_get_multiple,
487     HTMLSelectElement_put_name,
488     HTMLSelectElement_get_name,
489     HTMLSelectElement_get_options,
490     HTMLSelectElement_put_onchange,
491     HTMLSelectElement_get_onchange,
492     HTMLSelectElement_put_selectedIndex,
493     HTMLSelectElement_get_selectedIndex,
494     HTMLSelectElement_get_type,
495     HTMLSelectElement_put_value,
496     HTMLSelectElement_get_value,
497     HTMLSelectElement_put_disabled,
498     HTMLSelectElement_get_disabled,
499     HTMLSelectElement_get_form,
500     HTMLSelectElement_add,
501     HTMLSelectElement_remove,
502     HTMLSelectElement_put_length,
503     HTMLSelectElement_get_length,
504     HTMLSelectElement_get__newEnum,
505     HTMLSelectElement_item,
506     HTMLSelectElement_tags
507 };
508
509 static inline HTMLSelectElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface)
510 {
511     return CONTAINING_RECORD(iface, HTMLSelectElement, element.node);
512 }
513
514 static HRESULT HTMLSelectElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
515 {
516     HTMLSelectElement *This = impl_from_HTMLDOMNode(iface);
517
518     *ppv = NULL;
519
520     if(IsEqualGUID(&IID_IUnknown, riid)) {
521         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
522         *ppv = &This->IHTMLSelectElement_iface;
523     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
524         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
525         *ppv = &This->IHTMLSelectElement_iface;
526     }else if(IsEqualGUID(&IID_IHTMLSelectElement, riid)) {
527         TRACE("(%p)->(IID_IHTMLSelectElement %p)\n", This, ppv);
528         *ppv = &This->IHTMLSelectElement_iface;
529     }
530
531     if(*ppv) {
532         IUnknown_AddRef((IUnknown*)*ppv);
533         return S_OK;
534     }
535
536     return HTMLElement_QI(&This->element.node, riid, ppv);
537 }
538
539 static void HTMLSelectElement_destructor(HTMLDOMNode *iface)
540 {
541     HTMLSelectElement *This = impl_from_HTMLDOMNode(iface);
542
543     nsIDOMHTMLSelectElement_Release(This->nsselect);
544
545     HTMLElement_destructor(&This->element.node);
546 }
547
548 static HRESULT HTMLSelectElementImpl_put_disabled(HTMLDOMNode *iface, VARIANT_BOOL v)
549 {
550     HTMLSelectElement *This = impl_from_HTMLDOMNode(iface);
551     return IHTMLSelectElement_put_disabled(&This->IHTMLSelectElement_iface, v);
552 }
553
554 static HRESULT HTMLSelectElementImpl_get_disabled(HTMLDOMNode *iface, VARIANT_BOOL *p)
555 {
556     HTMLSelectElement *This = impl_from_HTMLDOMNode(iface);
557     return IHTMLSelectElement_get_disabled(&This->IHTMLSelectElement_iface, p);
558 }
559
560 #define DISPID_OPTIONCOL_0 MSHTML_DISPID_CUSTOM_MIN
561
562 static HRESULT HTMLSelectElement_get_dispid(HTMLDOMNode *iface, BSTR name, DWORD flags, DISPID *dispid)
563 {
564     const WCHAR *ptr;
565     DWORD idx = 0;
566
567     for(ptr = name; *ptr && isdigitW(*ptr); ptr++) {
568         idx = idx*10 + (*ptr-'0');
569         if(idx > MSHTML_CUSTOM_DISPID_CNT) {
570             WARN("too big idx\n");
571             return DISP_E_UNKNOWNNAME;
572         }
573     }
574     if(*ptr)
575         return DISP_E_UNKNOWNNAME;
576
577     *dispid = DISPID_OPTIONCOL_0 + idx;
578     return S_OK;
579 }
580
581 static HRESULT HTMLSelectElement_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
582         VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
583 {
584     HTMLSelectElement *This = impl_from_HTMLDOMNode(iface);
585
586     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
587
588     switch(flags) {
589     case DISPATCH_PROPERTYGET: {
590         IDispatch *ret;
591         HRESULT hres;
592
593         hres = htmlselect_item(This, id-DISPID_OPTIONCOL_0, &ret);
594         if(FAILED(hres))
595             return hres;
596
597         if(ret) {
598             V_VT(res) = VT_DISPATCH;
599             V_DISPATCH(res) = ret;
600         }else {
601             V_VT(res) = VT_NULL;
602         }
603         break;
604     }
605
606     default:
607         FIXME("unimplemented flags %x\n", flags);
608         return E_NOTIMPL;
609     }
610
611     return S_OK;
612 }
613
614 static const NodeImplVtbl HTMLSelectElementImplVtbl = {
615     HTMLSelectElement_QI,
616     HTMLSelectElement_destructor,
617     HTMLElement_clone,
618     NULL,
619     NULL,
620     NULL,
621     HTMLSelectElementImpl_put_disabled,
622     HTMLSelectElementImpl_get_disabled,
623     NULL,
624     NULL,
625     HTMLSelectElement_get_dispid,
626     HTMLSelectElement_invoke
627 };
628
629 static const tid_t HTMLSelectElement_tids[] = {
630     HTMLELEMENT_TIDS,
631     IHTMLSelectElement_tid,
632     0
633 };
634
635 static dispex_static_data_t HTMLSelectElement_dispex = {
636     NULL,
637     DispHTMLSelectElement_tid,
638     NULL,
639     HTMLSelectElement_tids
640 };
641
642 HRESULT HTMLSelectElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem, HTMLElement **elem)
643 {
644     HTMLSelectElement *ret;
645     nsresult nsres;
646
647     ret = heap_alloc_zero(sizeof(HTMLSelectElement));
648     if(!ret)
649         return E_OUTOFMEMORY;
650
651     ret->IHTMLSelectElement_iface.lpVtbl = &HTMLSelectElementVtbl;
652     ret->element.node.vtbl = &HTMLSelectElementImplVtbl;
653
654     nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLSelectElement,
655                                              (void**)&ret->nsselect);
656     if(NS_FAILED(nsres)) {
657         ERR("Could not get nsIDOMHTMLSelectElement interfce: %08x\n", nsres);
658         heap_free(ret);
659         return E_FAIL;
660     }
661
662     HTMLElement_Init(&ret->element, doc, nselem, &HTMLSelectElement_dispex);
663
664     *elem = &ret->element;
665     return S_OK;
666 }