user32/tests: Add a test for OpenClipboard twice with non-zero hwnd.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 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 <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27 static DISPID propput_dispid = DISPID_PROPERTYPUT;
28
29 typedef struct {
30     vbscode_t *code;
31     instr_t *instr;
32     script_ctx_t *script;
33     function_t *func;
34     IDispatch *this_obj;
35
36     VARIANT *args;
37     VARIANT *vars;
38
39     dynamic_var_t *dynamic_vars;
40     vbsheap_t heap;
41
42     BOOL resume_next;
43
44     unsigned stack_size;
45     unsigned top;
46     VARIANT *stack;
47
48     VARIANT ret_val;
49 } exec_ctx_t;
50
51 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
52
53 typedef enum {
54     REF_NONE,
55     REF_DISP,
56     REF_VAR,
57     REF_OBJ,
58     REF_CONST,
59     REF_FUNC
60 } ref_type_t;
61
62 typedef struct {
63     ref_type_t type;
64     union {
65         struct {
66             IDispatch *disp;
67             DISPID id;
68         } d;
69         VARIANT *v;
70         function_t *f;
71         IDispatch *obj;
72     } u;
73 } ref_t;
74
75 typedef struct {
76     VARIANT *v;
77     VARIANT store;
78     BOOL owned;
79 } variant_val_t;
80
81 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
82 {
83     while(var) {
84         if(!strcmpiW(var->name, name)) {
85             ref->type = var->is_const ? REF_CONST : REF_VAR;
86             ref->u.v = &var->v;
87             return TRUE;
88         }
89
90         var = var->next;
91     }
92
93     return FALSE;
94 }
95
96 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
97 {
98     named_item_t *item;
99     function_t *func;
100     unsigned i;
101     DISPID id;
102     HRESULT hres;
103
104     static const WCHAR errW[] = {'e','r','r',0};
105
106     if(invoke_type == VBDISP_LET
107             && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET || ctx->func->type == FUNC_DEFGET)
108             && !strcmpiW(name, ctx->func->name)) {
109         ref->type = REF_VAR;
110         ref->u.v = &ctx->ret_val;
111         return S_OK;
112     }
113
114     for(i=0; i < ctx->func->var_cnt; i++) {
115         if(!strcmpiW(ctx->func->vars[i].name, name)) {
116             ref->type = REF_VAR;
117             ref->u.v = ctx->vars+i;
118             return TRUE;
119         }
120     }
121
122     for(i=0; i < ctx->func->arg_cnt; i++) {
123         if(!strcmpiW(ctx->func->args[i].name, name)) {
124             ref->type = REF_VAR;
125             ref->u.v = ctx->args+i;
126             return S_OK;
127         }
128     }
129
130     if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
131         return S_OK;
132
133     if(ctx->func->type != FUNC_GLOBAL) {
134         hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id);
135         if(SUCCEEDED(hres)) {
136             ref->type = REF_DISP;
137             ref->u.d.disp = ctx->this_obj;
138             ref->u.d.id = id;
139             return S_OK;
140         }
141     }
142
143     if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
144         return S_OK;
145
146     for(func = ctx->script->global_funcs; func; func = func->next) {
147         if(!strcmpiW(func->name, name)) {
148             ref->type = REF_FUNC;
149             ref->u.f = func;
150             return S_OK;
151         }
152     }
153
154     if(!strcmpiW(name, errW)) {
155         ref->type = REF_OBJ;
156         ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface;
157         return S_OK;
158     }
159
160     hres = vbdisp_get_id(ctx->script->global_obj, name, invoke_type, TRUE, &id);
161     if(SUCCEEDED(hres)) {
162         ref->type = REF_DISP;
163         ref->u.d.disp = (IDispatch*)&ctx->script->global_obj->IDispatchEx_iface;
164         ref->u.d.id = id;
165         return S_OK;
166     }
167
168     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
169         if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpiW(item->name, name)) {
170             if(!item->disp) {
171                 IUnknown *unk;
172
173                 hres = IActiveScriptSite_GetItemInfo(ctx->script->site, name, SCRIPTINFO_IUNKNOWN, &unk, NULL);
174                 if(FAILED(hres)) {
175                     WARN("GetItemInfo failed: %08x\n", hres);
176                     continue;
177                 }
178
179                 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
180                 IUnknown_Release(unk);
181                 if(FAILED(hres)) {
182                     WARN("object does not implement IDispatch\n");
183                     continue;
184                 }
185             }
186
187             ref->type = REF_OBJ;
188             ref->u.obj = item->disp;
189             return S_OK;
190         }
191     }
192
193     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
194         if((item->flags & SCRIPTITEM_GLOBALMEMBERS)) {
195             hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id);
196             if(SUCCEEDED(hres)) {
197                 ref->type = REF_DISP;
198                 ref->u.d.disp = item->disp;
199                 ref->u.d.id = id;
200                 return S_OK;
201             }
202         }
203     }
204
205     ref->type = REF_NONE;
206     return S_OK;
207 }
208
209 static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, BOOL is_const, VARIANT *val, BOOL own_val)
210 {
211     dynamic_var_t *new_var;
212     vbsheap_t *heap;
213     WCHAR *str;
214     unsigned size;
215     HRESULT hres;
216
217     heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap;
218
219     new_var = vbsheap_alloc(heap, sizeof(*new_var));
220     if(!new_var)
221         return E_OUTOFMEMORY;
222
223     size = (strlenW(name)+1)*sizeof(WCHAR);
224     str = vbsheap_alloc(heap, size);
225     if(!str)
226         return E_OUTOFMEMORY;
227     memcpy(str, name, size);
228     new_var->name = str;
229     new_var->is_const = is_const;
230
231     if(own_val) {
232         new_var->v = *val;
233     }else {
234         V_VT(&new_var->v) = VT_EMPTY;
235         hres = VariantCopy(&new_var->v, val);
236         if(FAILED(hres))
237             return hres;
238     }
239
240     if(ctx->func->type == FUNC_GLOBAL) {
241         new_var->next = ctx->script->global_vars;
242         ctx->script->global_vars = new_var;
243     }else {
244         new_var->next = ctx->dynamic_vars;
245         ctx->dynamic_vars = new_var;
246     }
247
248     return S_OK;
249 }
250
251 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
252 {
253     assert(ctx->top);
254     return ctx->stack + --ctx->top;
255 }
256
257 static inline VARIANT *stack_top(exec_ctx_t *ctx, unsigned n)
258 {
259     assert(ctx->top >= n);
260     return ctx->stack + (ctx->top-n-1);
261 }
262
263 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
264 {
265     if(ctx->stack_size == ctx->top) {
266         VARIANT *new_stack;
267
268         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack));
269         if(!new_stack) {
270             VariantClear(v);
271             return E_OUTOFMEMORY;
272         }
273
274         ctx->stack = new_stack;
275         ctx->stack_size *= 2;
276     }
277
278     ctx->stack[ctx->top++] = *v;
279     return S_OK;
280 }
281
282 static void stack_popn(exec_ctx_t *ctx, unsigned n)
283 {
284     while(n--)
285         VariantClear(stack_pop(ctx));
286 }
287
288 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
289 {
290     VARIANT *var;
291
292     var = stack_pop(ctx);
293
294     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
295         v->owned = FALSE;
296         var = V_VARIANTREF(var);
297     }else {
298         v->owned = TRUE;
299     }
300
301     if(V_VT(var) == VT_DISPATCH) {
302         DISPPARAMS dp = {0};
303         HRESULT hres;
304
305         hres = disp_call(ctx->script, V_DISPATCH(var), DISPID_VALUE, &dp, &v->store);
306         if(v->owned)
307             IDispatch_Release(V_DISPATCH(var));
308         if(FAILED(hres))
309             return hres;
310
311         v->owned = TRUE;
312         v->v = &v->store;
313     }else {
314         v->v = var;
315     }
316
317     return S_OK;
318 }
319
320 static HRESULT stack_assume_val(exec_ctx_t *ctx, unsigned n)
321 {
322     VARIANT *v = stack_top(ctx, n);
323     HRESULT hres;
324
325     if(V_VT(v) == (VT_BYREF|VT_VARIANT)) {
326         VARIANT *ref = V_VARIANTREF(v);
327
328         V_VT(v) = VT_EMPTY;
329         hres = VariantCopy(v, ref);
330         if(FAILED(hres))
331             return hres;
332     }
333
334     if(V_VT(v) == VT_DISPATCH) {
335         DISPPARAMS dp = {0};
336         IDispatch *disp;
337
338         disp = V_DISPATCH(v);
339         V_VT(v) = VT_EMPTY;
340         hres = disp_call(ctx->script, disp, DISPID_VALUE, &dp, v);
341         IDispatch_Release(disp);
342         if(FAILED(hres))
343             return hres;
344     }
345
346     return S_OK;
347 }
348
349 static inline void release_val(variant_val_t *v)
350 {
351     if(v->owned)
352         VariantClear(v->v);
353 }
354
355 static int stack_pop_bool(exec_ctx_t *ctx, BOOL *b)
356 {
357     variant_val_t val;
358     HRESULT hres;
359
360     hres = stack_pop_val(ctx, &val);
361     if(FAILED(hres))
362         return hres;
363
364     switch (V_VT(val.v))
365     {
366     case VT_BOOL:
367         *b = V_BOOL(val.v);
368         break;
369     case VT_I2:
370         *b = V_I2(val.v);
371         break;
372     case VT_I4:
373         *b = V_I4(val.v);
374         break;
375     default:
376         FIXME("unsupported for %s\n", debugstr_variant(val.v));
377         release_val(&val);
378         return E_NOTIMPL;
379     }
380     return S_OK;
381 }
382
383 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
384 {
385     VARIANT *v = stack_pop(ctx);
386
387     if(V_VT(v) == VT_DISPATCH) {
388         *ret = V_DISPATCH(v);
389         return S_OK;
390     }
391
392     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
393         FIXME("not supported type: %s\n", debugstr_variant(v));
394         VariantClear(v);
395         return E_FAIL;
396     }
397
398     v = V_BYREF(v);
399     if(V_VT(v) != VT_DISPATCH) {
400         FIXME("not disp %s\n", debugstr_variant(v));
401         return E_FAIL;
402     }
403
404     if(V_DISPATCH(v))
405         IDispatch_AddRef(V_DISPATCH(v));
406     *ret = V_DISPATCH(v);
407     return S_OK;
408 }
409
410 static HRESULT stack_assume_disp(exec_ctx_t *ctx, unsigned n, IDispatch **disp)
411 {
412     VARIANT *v = stack_top(ctx, n), *ref;
413
414     if(V_VT(v) != VT_DISPATCH) {
415         if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
416             FIXME("not supported type: %s\n", debugstr_variant(v));
417             return E_FAIL;
418         }
419
420         ref = V_VARIANTREF(v);
421         if(V_VT(ref) != VT_DISPATCH) {
422             FIXME("not disp %s\n", debugstr_variant(ref));
423             return E_FAIL;
424         }
425
426         V_VT(v) = VT_DISPATCH;
427         V_DISPATCH(v) = V_DISPATCH(ref);
428         if(V_DISPATCH(v))
429             IDispatch_AddRef(V_DISPATCH(v));
430     }
431
432     if(disp)
433         *disp = V_DISPATCH(v);
434     return S_OK;
435 }
436
437 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
438 {
439     ctx->instr = ctx->code->instrs + addr;
440 }
441
442 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, BOOL is_propput, DISPPARAMS *dp)
443 {
444     dp->cNamedArgs = is_propput ? 1 : 0;
445     dp->cArgs = arg_cnt + dp->cNamedArgs;
446     dp->rgdispidNamedArgs = is_propput ? &propput_dispid : NULL;
447
448     if(arg_cnt) {
449         VARIANT tmp;
450         unsigned i;
451
452         assert(ctx->top >= arg_cnt);
453
454         for(i=1; i*2 <= arg_cnt; i++) {
455             tmp = ctx->stack[ctx->top-i];
456             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
457             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
458         }
459
460         dp->rgvarg = ctx->stack + ctx->top-dp->cArgs;
461     }else {
462         dp->rgvarg = is_propput ? ctx->stack+ctx->top-1 : NULL;
463     }
464 }
465
466 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
467 {
468     BSTR identifier = ctx->instr->arg1.bstr;
469     const unsigned arg_cnt = ctx->instr->arg2.uint;
470     DISPPARAMS dp;
471     ref_t ref;
472     HRESULT hres;
473
474     hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
475     if(FAILED(hres))
476         return hres;
477
478     vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
479
480     switch(ref.type) {
481     case REF_VAR:
482     case REF_CONST:
483         if(!res) {
484             FIXME("REF_VAR no res\n");
485             return E_NOTIMPL;
486         }
487
488         if(arg_cnt) {
489             FIXME("arguments not implemented\n");
490             return E_NOTIMPL;
491         }
492
493         V_VT(res) = VT_BYREF|VT_VARIANT;
494         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
495         break;
496     case REF_DISP:
497         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
498         if(FAILED(hres))
499             return hres;
500         break;
501     case REF_FUNC:
502         hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
503         if(FAILED(hres))
504             return hres;
505         break;
506     case REF_OBJ:
507         if(arg_cnt) {
508             FIXME("arguments on object\n");
509             return E_NOTIMPL;
510         }
511
512         if(res) {
513             IDispatch_AddRef(ref.u.obj);
514             V_VT(res) = VT_DISPATCH;
515             V_DISPATCH(res) = ref.u.obj;
516         }
517         break;
518     case REF_NONE:
519         FIXME("%s not found\n", debugstr_w(identifier));
520         return DISP_E_UNKNOWNNAME;
521     }
522
523     stack_popn(ctx, arg_cnt);
524     return S_OK;
525 }
526
527 static HRESULT interp_icall(exec_ctx_t *ctx)
528 {
529     VARIANT v;
530     HRESULT hres;
531
532     TRACE("\n");
533
534     hres = do_icall(ctx, &v);
535     if(FAILED(hres))
536         return hres;
537
538     return stack_push(ctx, &v);
539 }
540
541 static HRESULT interp_icallv(exec_ctx_t *ctx)
542 {
543     TRACE("\n");
544     return do_icall(ctx, NULL);
545 }
546
547 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
548 {
549     const BSTR identifier = ctx->instr->arg1.bstr;
550     const unsigned arg_cnt = ctx->instr->arg2.uint;
551     IDispatch *obj;
552     DISPPARAMS dp;
553     DISPID id;
554     HRESULT hres;
555
556     hres = stack_pop_disp(ctx, &obj);
557     if(FAILED(hres))
558         return hres;
559
560     if(!obj) {
561         FIXME("NULL obj\n");
562         return E_FAIL;
563     }
564
565     vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
566
567     hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
568     if(SUCCEEDED(hres))
569         hres = disp_call(ctx->script, obj, id, &dp, res);
570     IDispatch_Release(obj);
571     if(FAILED(hres))
572         return hres;
573
574     stack_popn(ctx, arg_cnt);
575     return S_OK;
576 }
577
578 static HRESULT interp_mcall(exec_ctx_t *ctx)
579 {
580     VARIANT res;
581     HRESULT hres;
582
583     TRACE("\n");
584
585     hres = do_mcall(ctx, &res);
586     if(FAILED(hres))
587         return hres;
588
589     return stack_push(ctx, &res);
590 }
591
592 static HRESULT interp_mcallv(exec_ctx_t *ctx)
593 {
594     TRACE("\n");
595
596     return do_mcall(ctx, NULL);
597 }
598
599 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, DISPPARAMS *dp)
600 {
601     ref_t ref;
602     HRESULT hres;
603
604     hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
605     if(FAILED(hres))
606         return hres;
607
608     switch(ref.type) {
609     case REF_VAR: {
610         VARIANT *v = ref.u.v;
611
612         if(arg_cnt(dp)) {
613             FIXME("arg_cnt %d not supported\n", arg_cnt(dp));
614             return E_NOTIMPL;
615         }
616
617         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
618             v = V_VARIANTREF(v);
619
620         hres = VariantCopy(v, dp->rgvarg);
621         break;
622     }
623     case REF_DISP:
624         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, dp);
625         break;
626     case REF_FUNC:
627         FIXME("functions not implemented\n");
628         return E_NOTIMPL;
629     case REF_OBJ:
630         FIXME("REF_OBJ\n");
631         return E_NOTIMPL;
632     case REF_CONST:
633         FIXME("REF_CONST\n");
634         return E_NOTIMPL;
635     case REF_NONE:
636         if(ctx->func->code_ctx->option_explicit) {
637             FIXME("throw exception\n");
638             hres = E_FAIL;
639         }else {
640             if(arg_cnt(dp)) {
641                 FIXME("arg_cnt %d not supported\n", arg_cnt(dp));
642                 return E_NOTIMPL;
643             }
644
645             TRACE("creating variable %s\n", debugstr_w(name));
646             hres = add_dynamic_var(ctx, name, FALSE, dp->rgvarg, FALSE);
647         }
648     }
649
650     return hres;
651 }
652
653 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
654 {
655     const BSTR arg = ctx->instr->arg1.bstr;
656     const unsigned arg_cnt = ctx->instr->arg2.uint;
657     DISPPARAMS dp;
658     HRESULT hres;
659
660     TRACE("%s\n", debugstr_w(arg));
661
662     hres = stack_assume_val(ctx, arg_cnt);
663     if(FAILED(hres))
664         return hres;
665
666     vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
667     hres = assign_ident(ctx, arg, &dp);
668     if(FAILED(hres))
669         return hres;
670
671     stack_popn(ctx, arg_cnt+1);
672     return S_OK;
673 }
674
675 static HRESULT interp_set_ident(exec_ctx_t *ctx)
676 {
677     const BSTR arg = ctx->instr->arg1.bstr;
678     const unsigned arg_cnt = ctx->instr->arg2.uint;
679     DISPPARAMS dp;
680     HRESULT hres;
681
682     TRACE("%s\n", debugstr_w(arg));
683
684     if(arg_cnt) {
685         FIXME("arguments not supported\n");
686         return E_NOTIMPL;
687     }
688
689     hres = stack_assume_disp(ctx, 0, NULL);
690     if(FAILED(hres))
691         return hres;
692
693     vbstack_to_dp(ctx, 0, TRUE, &dp);
694     hres = assign_ident(ctx, ctx->instr->arg1.bstr, &dp);
695     if(FAILED(hres))
696         return hres;
697
698     stack_popn(ctx, 1);
699     return S_OK;
700 }
701
702 static HRESULT interp_assign_member(exec_ctx_t *ctx)
703 {
704     BSTR identifier = ctx->instr->arg1.bstr;
705     const unsigned arg_cnt = ctx->instr->arg2.uint;
706     IDispatch *obj;
707     DISPPARAMS dp;
708     DISPID id;
709     HRESULT hres;
710
711     TRACE("%s\n", debugstr_w(identifier));
712
713     hres = stack_assume_disp(ctx, arg_cnt+1, &obj);
714     if(FAILED(hres))
715         return hres;
716
717     if(!obj) {
718         FIXME("NULL obj\n");
719         return E_FAIL;
720     }
721
722     hres = stack_assume_val(ctx, arg_cnt);
723     if(FAILED(hres))
724         return hres;
725
726     hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
727     if(SUCCEEDED(hres)) {
728         vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
729         hres = disp_propput(ctx->script, obj, id, &dp);
730     }
731     if(FAILED(hres))
732         return hres;
733
734     stack_popn(ctx, arg_cnt+2);
735     return S_OK;
736 }
737
738 static HRESULT interp_set_member(exec_ctx_t *ctx)
739 {
740     BSTR identifier = ctx->instr->arg1.bstr;
741     const unsigned arg_cnt = ctx->instr->arg2.uint;
742     IDispatch *obj;
743     DISPPARAMS dp;
744     DISPID id;
745     HRESULT hres;
746
747     TRACE("%s\n", debugstr_w(identifier));
748
749     if(arg_cnt) {
750         FIXME("arguments not supported\n");
751         return E_NOTIMPL;
752     }
753
754     hres = stack_assume_disp(ctx, 1, &obj);
755     if(FAILED(hres))
756         return hres;
757
758     if(!obj) {
759         FIXME("NULL obj\n");
760         return E_FAIL;
761     }
762
763     hres = stack_assume_disp(ctx, 0, NULL);
764     if(FAILED(hres))
765         return hres;
766
767     hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
768     if(SUCCEEDED(hres)) {
769         vbstack_to_dp(ctx, arg_cnt, TRUE, &dp);
770         hres = disp_propput(ctx->script, obj, id, &dp);
771     }
772     if(FAILED(hres))
773         return hres;
774
775     stack_popn(ctx, 2);
776     return S_OK;
777 }
778
779 static HRESULT interp_const(exec_ctx_t *ctx)
780 {
781     BSTR arg = ctx->instr->arg1.bstr;
782     variant_val_t val;
783     ref_t ref;
784     HRESULT hres;
785
786     TRACE("%s\n", debugstr_w(arg));
787
788     assert(ctx->func->type == FUNC_GLOBAL);
789
790     hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref);
791     if(FAILED(hres))
792         return hres;
793
794     if(ref.type != REF_NONE) {
795         FIXME("%s already defined\n", debugstr_w(arg));
796         return E_FAIL;
797     }
798
799     hres = stack_pop_val(ctx, &val);
800     if(FAILED(hres))
801         return hres;
802
803     return add_dynamic_var(ctx, arg, TRUE, val.v, val.owned);
804 }
805
806 static HRESULT interp_val(exec_ctx_t *ctx)
807 {
808     variant_val_t val;
809     VARIANT v;
810     HRESULT hres;
811
812     TRACE("\n");
813
814     hres = stack_pop_val(ctx, &val);
815     if(FAILED(hres))
816         return hres;
817
818     if(!val.owned) {
819         V_VT(&v) = VT_EMPTY;
820         hres = VariantCopy(&v, val.v);
821         if(FAILED(hres))
822             return hres;
823     }
824
825     return stack_push(ctx, val.owned ? val.v : &v);
826 }
827
828 static HRESULT interp_pop(exec_ctx_t *ctx)
829 {
830     const unsigned n = ctx->instr->arg1.uint;
831
832     TRACE("%u\n", n);
833
834     stack_popn(ctx, n);
835     return S_OK;
836 }
837
838 static HRESULT interp_new(exec_ctx_t *ctx)
839 {
840     const WCHAR *arg = ctx->instr->arg1.bstr;
841     class_desc_t *class_desc;
842     vbdisp_t *obj;
843     VARIANT v;
844     HRESULT hres;
845
846     TRACE("%s\n", debugstr_w(arg));
847
848     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
849         if(!strcmpiW(class_desc->name, arg))
850             break;
851     }
852     if(!class_desc) {
853         FIXME("Class %s not found\n", debugstr_w(arg));
854         return E_FAIL;
855     }
856
857     hres = create_vbdisp(class_desc, &obj);
858     if(FAILED(hres))
859         return hres;
860
861     V_VT(&v) = VT_DISPATCH;
862     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
863     return stack_push(ctx, &v);
864 }
865
866 static HRESULT interp_step(exec_ctx_t *ctx)
867 {
868     const BSTR ident = ctx->instr->arg2.bstr;
869     BOOL gteq_zero;
870     VARIANT zero;
871     ref_t ref;
872     HRESULT hres;
873
874     TRACE("%s\n", debugstr_w(ident));
875
876     V_VT(&zero) = VT_I2;
877     V_I2(&zero) = 0;
878     hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0);
879     if(FAILED(hres))
880         return hres;
881
882     gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ;
883
884     hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref);
885     if(FAILED(hres))
886         return hres;
887
888     if(ref.type != REF_VAR) {
889         FIXME("%s is not REF_VAR\n", debugstr_w(ident));
890         return E_FAIL;
891     }
892
893     hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0);
894     if(FAILED(hres))
895         return hres;
896
897     if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT)) {
898         ctx->instr++;
899     }else {
900         stack_popn(ctx, 2);
901         instr_jmp(ctx, ctx->instr->arg1.uint);
902     }
903     return S_OK;
904 }
905
906 static HRESULT interp_newenum(exec_ctx_t *ctx)
907 {
908     VARIANT *v, r;
909     HRESULT hres;
910
911     TRACE("\n");
912
913     v = stack_pop(ctx);
914     switch(V_VT(v)) {
915     case VT_DISPATCH: {
916         IEnumVARIANT *iter;
917         DISPPARAMS dp = {0};
918         VARIANT iterv;
919
920         hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_NEWENUM, &dp, &iterv);
921         VariantClear(v);
922         if(FAILED(hres))
923             return hres;
924
925         if(V_VT(&iterv) != VT_UNKNOWN && V_VT(&iterv) != VT_DISPATCH) {
926             FIXME("Unsupported iterv %s\n", debugstr_variant(&iterv));
927             VariantClear(&iterv);
928             return hres;
929         }
930
931         hres = IUnknown_QueryInterface(V_UNKNOWN(&iterv), &IID_IEnumVARIANT, (void**)&iter);
932         IUnknown_Release(V_UNKNOWN(&iterv));
933         if(FAILED(hres)) {
934             FIXME("Could not get IEnumVARIANT iface: %08x\n", hres);
935             return hres;
936         }
937
938         V_VT(&r) = VT_UNKNOWN;
939         V_UNKNOWN(&r) = (IUnknown*)iter;
940         break;
941     }
942     default:
943         FIXME("Unsupported for %s\n", debugstr_variant(v));
944         VariantClear(v);
945         return E_NOTIMPL;
946     }
947
948     return stack_push(ctx, &r);
949 }
950
951 static HRESULT interp_enumnext(exec_ctx_t *ctx)
952 {
953     const unsigned loop_end = ctx->instr->arg1.uint;
954     const BSTR ident = ctx->instr->arg2.bstr;
955     VARIANT v;
956     DISPPARAMS dp = {&v, &propput_dispid, 1, 1};
957     IEnumVARIANT *iter;
958     BOOL do_continue;
959     HRESULT hres;
960
961     TRACE("\n");
962
963     assert(V_VT(stack_top(ctx, 0)) == VT_UNKNOWN);
964     iter = (IEnumVARIANT*)V_UNKNOWN(stack_top(ctx, 0));
965
966     V_VT(&v) = VT_EMPTY;
967     hres = IEnumVARIANT_Next(iter, 1, &v, NULL);
968     if(FAILED(hres))
969         return hres;
970
971     do_continue = hres == S_OK;
972     hres = assign_ident(ctx, ident, &dp);
973     VariantClear(&v);
974     if(FAILED(hres))
975         return hres;
976
977     if(do_continue) {
978         ctx->instr++;
979     }else {
980         stack_pop(ctx);
981         instr_jmp(ctx, loop_end);
982     }
983     return S_OK;
984 }
985
986 static HRESULT interp_jmp(exec_ctx_t *ctx)
987 {
988     const unsigned arg = ctx->instr->arg1.uint;
989
990     TRACE("%u\n", arg);
991
992     instr_jmp(ctx, arg);
993     return S_OK;
994 }
995
996 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
997 {
998     const unsigned arg = ctx->instr->arg1.uint;
999     HRESULT hres;
1000     BOOL b;
1001
1002     TRACE("%u\n", arg);
1003
1004     hres = stack_pop_bool(ctx, &b);
1005     if(FAILED(hres))
1006         return hres;
1007
1008     if(b)
1009         ctx->instr++;
1010     else
1011         instr_jmp(ctx, ctx->instr->arg1.uint);
1012     return S_OK;
1013 }
1014
1015 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
1016 {
1017     const unsigned arg = ctx->instr->arg1.uint;
1018     HRESULT hres;
1019     BOOL b;
1020
1021     TRACE("%u\n", arg);
1022
1023     hres = stack_pop_bool(ctx, &b);
1024     if(FAILED(hres))
1025         return hres;
1026
1027     if(b)
1028         instr_jmp(ctx, ctx->instr->arg1.uint);
1029     else
1030         ctx->instr++;
1031     return S_OK;
1032 }
1033
1034 static HRESULT interp_ret(exec_ctx_t *ctx)
1035 {
1036     TRACE("\n");
1037
1038     ctx->instr = NULL;
1039     return S_OK;
1040 }
1041
1042 static HRESULT interp_stop(exec_ctx_t *ctx)
1043 {
1044     WARN("\n");
1045
1046     /* NOTE: this should have effect in debugging mode (that we don't support yet) */
1047     return S_OK;
1048 }
1049
1050 static HRESULT interp_me(exec_ctx_t *ctx)
1051 {
1052     VARIANT v;
1053
1054     TRACE("\n");
1055
1056     IDispatch_AddRef(ctx->this_obj);
1057     V_VT(&v) = VT_DISPATCH;
1058     V_DISPATCH(&v) = ctx->this_obj;
1059     return stack_push(ctx, &v);
1060 }
1061
1062 static HRESULT interp_bool(exec_ctx_t *ctx)
1063 {
1064     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
1065     VARIANT v;
1066
1067     TRACE("%s\n", arg ? "true" : "false");
1068
1069     V_VT(&v) = VT_BOOL;
1070     V_BOOL(&v) = arg;
1071     return stack_push(ctx, &v);
1072 }
1073
1074 static HRESULT interp_errmode(exec_ctx_t *ctx)
1075 {
1076     const int err_mode = ctx->instr->arg1.uint;
1077
1078     TRACE("%d\n", err_mode);
1079
1080     ctx->resume_next = err_mode;
1081     return S_OK;
1082 }
1083
1084 static HRESULT interp_string(exec_ctx_t *ctx)
1085 {
1086     VARIANT v;
1087
1088     TRACE("\n");
1089
1090     V_VT(&v) = VT_BSTR;
1091     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
1092     if(!V_BSTR(&v))
1093         return E_OUTOFMEMORY;
1094
1095     return stack_push(ctx, &v);
1096 }
1097
1098 static HRESULT interp_long(exec_ctx_t *ctx)
1099 {
1100     const LONG arg = ctx->instr->arg1.lng;
1101     VARIANT v;
1102
1103     TRACE("%d\n", arg);
1104
1105     V_VT(&v) = VT_I4;
1106     V_I4(&v) = arg;
1107     return stack_push(ctx, &v);
1108 }
1109
1110 static HRESULT interp_short(exec_ctx_t *ctx)
1111 {
1112     const LONG arg = ctx->instr->arg1.lng;
1113     VARIANT v;
1114
1115     TRACE("%d\n", arg);
1116
1117     V_VT(&v) = VT_I2;
1118     V_I2(&v) = arg;
1119     return stack_push(ctx, &v);
1120 }
1121
1122 static HRESULT interp_double(exec_ctx_t *ctx)
1123 {
1124     const DOUBLE *arg = ctx->instr->arg1.dbl;
1125     VARIANT v;
1126
1127     TRACE("%lf\n", *arg);
1128
1129     V_VT(&v) = VT_R8;
1130     V_R8(&v) = *arg;
1131     return stack_push(ctx, &v);
1132 }
1133
1134 static HRESULT interp_empty(exec_ctx_t *ctx)
1135 {
1136     VARIANT v;
1137
1138     TRACE("\n");
1139
1140     V_VT(&v) = VT_EMPTY;
1141     return stack_push(ctx, &v);
1142 }
1143
1144 static HRESULT interp_null(exec_ctx_t *ctx)
1145 {
1146     VARIANT v;
1147
1148     TRACE("\n");
1149
1150     V_VT(&v) = VT_NULL;
1151     return stack_push(ctx, &v);
1152 }
1153
1154 static HRESULT interp_nothing(exec_ctx_t *ctx)
1155 {
1156     VARIANT v;
1157
1158     TRACE("\n");
1159
1160     V_VT(&v) = VT_DISPATCH;
1161     V_DISPATCH(&v) = NULL;
1162     return stack_push(ctx, &v);
1163 }
1164
1165 static HRESULT interp_not(exec_ctx_t *ctx)
1166 {
1167     variant_val_t val;
1168     VARIANT v;
1169     HRESULT hres;
1170
1171     TRACE("\n");
1172
1173     hres = stack_pop_val(ctx, &val);
1174     if(FAILED(hres))
1175         return hres;
1176
1177     hres = VarNot(val.v, &v);
1178     release_val(&val);
1179     if(FAILED(hres))
1180         return hres;
1181
1182     return stack_push(ctx, &v);
1183 }
1184
1185 static HRESULT interp_and(exec_ctx_t *ctx)
1186 {
1187     variant_val_t r, l;
1188     VARIANT v;
1189     HRESULT hres;
1190
1191     TRACE("\n");
1192
1193     hres = stack_pop_val(ctx, &r);
1194     if(FAILED(hres))
1195         return hres;
1196
1197     hres = stack_pop_val(ctx, &l);
1198     if(SUCCEEDED(hres)) {
1199         hres = VarAnd(l.v, r.v, &v);
1200         release_val(&l);
1201     }
1202     release_val(&r);
1203     if(FAILED(hres))
1204         return hres;
1205
1206     return stack_push(ctx, &v);
1207 }
1208
1209 static HRESULT interp_or(exec_ctx_t *ctx)
1210 {
1211     variant_val_t r, l;
1212     VARIANT v;
1213     HRESULT hres;
1214
1215     TRACE("\n");
1216
1217     hres = stack_pop_val(ctx, &r);
1218     if(FAILED(hres))
1219         return hres;
1220
1221     hres = stack_pop_val(ctx, &l);
1222     if(SUCCEEDED(hres)) {
1223         hres = VarOr(l.v, r.v, &v);
1224         release_val(&l);
1225     }
1226     release_val(&r);
1227     if(FAILED(hres))
1228         return hres;
1229
1230     return stack_push(ctx, &v);
1231 }
1232
1233 static HRESULT interp_xor(exec_ctx_t *ctx)
1234 {
1235     variant_val_t r, l;
1236     VARIANT v;
1237     HRESULT hres;
1238
1239     TRACE("\n");
1240
1241     hres = stack_pop_val(ctx, &r);
1242     if(FAILED(hres))
1243         return hres;
1244
1245     hres = stack_pop_val(ctx, &l);
1246     if(SUCCEEDED(hres)) {
1247         hres = VarXor(l.v, r.v, &v);
1248         release_val(&l);
1249     }
1250     release_val(&r);
1251     if(FAILED(hres))
1252         return hres;
1253
1254     return stack_push(ctx, &v);
1255 }
1256
1257 static HRESULT interp_eqv(exec_ctx_t *ctx)
1258 {
1259     variant_val_t r, l;
1260     VARIANT v;
1261     HRESULT hres;
1262
1263     TRACE("\n");
1264
1265     hres = stack_pop_val(ctx, &r);
1266     if(FAILED(hres))
1267         return hres;
1268
1269     hres = stack_pop_val(ctx, &l);
1270     if(SUCCEEDED(hres)) {
1271         hres = VarEqv(l.v, r.v, &v);
1272         release_val(&l);
1273     }
1274     release_val(&r);
1275     if(FAILED(hres))
1276         return hres;
1277
1278     return stack_push(ctx, &v);
1279 }
1280
1281 static HRESULT interp_imp(exec_ctx_t *ctx)
1282 {
1283     variant_val_t r, l;
1284     VARIANT v;
1285     HRESULT hres;
1286
1287     TRACE("\n");
1288
1289     hres = stack_pop_val(ctx, &r);
1290     if(FAILED(hres))
1291         return hres;
1292
1293     hres = stack_pop_val(ctx, &l);
1294     if(SUCCEEDED(hres)) {
1295         hres = VarImp(l.v, r.v, &v);
1296         release_val(&l);
1297     }
1298     release_val(&r);
1299     if(FAILED(hres))
1300         return hres;
1301
1302     return stack_push(ctx, &v);
1303 }
1304
1305 static HRESULT cmp_oper(exec_ctx_t *ctx)
1306 {
1307     variant_val_t l, r;
1308     HRESULT hres;
1309
1310     hres = stack_pop_val(ctx, &r);
1311     if(FAILED(hres))
1312         return hres;
1313
1314     hres = stack_pop_val(ctx, &l);
1315     if(SUCCEEDED(hres)) {
1316         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
1317             FIXME("comparing nulls is not implemented\n");
1318             hres = E_NOTIMPL;
1319         }else {
1320             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
1321         }
1322     }
1323
1324     release_val(&r);
1325     release_val(&l);
1326     return hres;
1327 }
1328
1329 static HRESULT interp_equal(exec_ctx_t *ctx)
1330 {
1331     VARIANT v;
1332     HRESULT hres;
1333
1334     TRACE("\n");
1335
1336     hres = cmp_oper(ctx);
1337     if(FAILED(hres))
1338         return hres;
1339
1340     V_VT(&v) = VT_BOOL;
1341     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1342     return stack_push(ctx, &v);
1343 }
1344
1345 static HRESULT interp_nequal(exec_ctx_t *ctx)
1346 {
1347     VARIANT v;
1348     HRESULT hres;
1349
1350     TRACE("\n");
1351
1352     hres = cmp_oper(ctx);
1353     if(FAILED(hres))
1354         return hres;
1355
1356     V_VT(&v) = VT_BOOL;
1357     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1358     return stack_push(ctx, &v);
1359 }
1360
1361 static HRESULT interp_gt(exec_ctx_t *ctx)
1362 {
1363     VARIANT v;
1364     HRESULT hres;
1365
1366     TRACE("\n");
1367
1368     hres = cmp_oper(ctx);
1369     if(FAILED(hres))
1370         return hres;
1371
1372     V_VT(&v) = VT_BOOL;
1373     V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1374     return stack_push(ctx, &v);
1375 }
1376
1377 static HRESULT interp_gteq(exec_ctx_t *ctx)
1378 {
1379     VARIANT v;
1380     HRESULT hres;
1381
1382     TRACE("\n");
1383
1384     hres = cmp_oper(ctx);
1385     if(FAILED(hres))
1386         return hres;
1387
1388     V_VT(&v) = VT_BOOL;
1389     V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1390     return stack_push(ctx, &v);
1391 }
1392
1393 static HRESULT interp_lt(exec_ctx_t *ctx)
1394 {
1395     VARIANT v;
1396     HRESULT hres;
1397
1398     TRACE("\n");
1399
1400     hres = cmp_oper(ctx);
1401     if(FAILED(hres))
1402         return hres;
1403
1404     V_VT(&v) = VT_BOOL;
1405     V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1406     return stack_push(ctx, &v);
1407 }
1408
1409 static HRESULT interp_lteq(exec_ctx_t *ctx)
1410 {
1411     VARIANT v;
1412     HRESULT hres;
1413
1414     TRACE("\n");
1415
1416     hres = cmp_oper(ctx);
1417     if(FAILED(hres))
1418         return hres;
1419
1420     V_VT(&v) = VT_BOOL;
1421     V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1422     return stack_push(ctx, &v);
1423 }
1424
1425 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1426 {
1427     IObjectIdentity *identity;
1428     IUnknown *unk1, *unk2;
1429     HRESULT hres;
1430
1431     if(disp1 == disp2) {
1432         *ret = VARIANT_TRUE;
1433         return S_OK;
1434     }
1435
1436     if(!disp1 || !disp2) {
1437         *ret = VARIANT_FALSE;
1438         return S_OK;
1439     }
1440
1441     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1442     if(FAILED(hres))
1443         return hres;
1444
1445     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1446     if(FAILED(hres)) {
1447         IUnknown_Release(unk1);
1448         return hres;
1449     }
1450
1451     if(unk1 == unk2) {
1452         *ret = VARIANT_TRUE;
1453     }else {
1454         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1455         if(SUCCEEDED(hres)) {
1456             hres = IObjectIdentity_IsEqualObject(identity, unk2);
1457             IObjectIdentity_Release(identity);
1458             *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1459         }else {
1460             *ret = VARIANT_FALSE;
1461         }
1462     }
1463
1464     IUnknown_Release(unk1);
1465     IUnknown_Release(unk2);
1466     return S_OK;
1467 }
1468
1469 static HRESULT interp_is(exec_ctx_t *ctx)
1470 {
1471     IDispatch *l, *r;
1472     VARIANT v;
1473     HRESULT hres;
1474
1475     TRACE("\n");
1476
1477     hres = stack_pop_disp(ctx, &r);
1478     if(FAILED(hres))
1479         return hres;
1480
1481     hres = stack_pop_disp(ctx, &l);
1482     if(SUCCEEDED(hres)) {
1483         V_VT(&v) = VT_BOOL;
1484         hres = disp_cmp(l, r, &V_BOOL(&v));
1485         if(l)
1486             IDispatch_Release(l);
1487     }
1488     if(r)
1489         IDispatch_Release(r);
1490     if(FAILED(hres))
1491         return hres;
1492
1493     return stack_push(ctx, &v);
1494 }
1495
1496 static HRESULT interp_concat(exec_ctx_t *ctx)
1497 {
1498     variant_val_t r, l;
1499     VARIANT v;
1500     HRESULT hres;
1501
1502     TRACE("\n");
1503
1504     hres = stack_pop_val(ctx, &r);
1505     if(FAILED(hres))
1506         return hres;
1507
1508     hres = stack_pop_val(ctx, &l);
1509     if(SUCCEEDED(hres)) {
1510         hres = VarCat(l.v, r.v, &v);
1511         release_val(&l);
1512     }
1513     release_val(&r);
1514     if(FAILED(hres))
1515         return hres;
1516
1517     return stack_push(ctx, &v);
1518 }
1519
1520 static HRESULT interp_add(exec_ctx_t *ctx)
1521 {
1522     variant_val_t r, l;
1523     VARIANT v;
1524     HRESULT hres;
1525
1526     TRACE("\n");
1527
1528     hres = stack_pop_val(ctx, &r);
1529     if(FAILED(hres))
1530         return hres;
1531
1532     hres = stack_pop_val(ctx, &l);
1533     if(SUCCEEDED(hres)) {
1534         hres = VarAdd(l.v, r.v, &v);
1535         release_val(&l);
1536     }
1537     release_val(&r);
1538     if(FAILED(hres))
1539         return hres;
1540
1541     return stack_push(ctx, &v);
1542 }
1543
1544 static HRESULT interp_sub(exec_ctx_t *ctx)
1545 {
1546     variant_val_t r, l;
1547     VARIANT v;
1548     HRESULT hres;
1549
1550     TRACE("\n");
1551
1552     hres = stack_pop_val(ctx, &r);
1553     if(FAILED(hres))
1554         return hres;
1555
1556     hres = stack_pop_val(ctx, &l);
1557     if(SUCCEEDED(hres)) {
1558         hres = VarSub(l.v, r.v, &v);
1559         release_val(&l);
1560     }
1561     release_val(&r);
1562     if(FAILED(hres))
1563         return hres;
1564
1565     return stack_push(ctx, &v);
1566 }
1567
1568 static HRESULT interp_mod(exec_ctx_t *ctx)
1569 {
1570     variant_val_t r, l;
1571     VARIANT v;
1572     HRESULT hres;
1573
1574     TRACE("\n");
1575
1576     hres = stack_pop_val(ctx, &r);
1577     if(FAILED(hres))
1578         return hres;
1579
1580     hres = stack_pop_val(ctx, &l);
1581     if(SUCCEEDED(hres)) {
1582         hres = VarMod(l.v, r.v, &v);
1583         release_val(&l);
1584     }
1585     release_val(&r);
1586     if(FAILED(hres))
1587         return hres;
1588
1589     return stack_push(ctx, &v);
1590 }
1591
1592 static HRESULT interp_idiv(exec_ctx_t *ctx)
1593 {
1594     variant_val_t r, l;
1595     VARIANT v;
1596     HRESULT hres;
1597
1598     TRACE("\n");
1599
1600     hres = stack_pop_val(ctx, &r);
1601     if(FAILED(hres))
1602         return hres;
1603
1604     hres = stack_pop_val(ctx, &l);
1605     if(SUCCEEDED(hres)) {
1606         hres = VarIdiv(l.v, r.v, &v);
1607         release_val(&l);
1608     }
1609     release_val(&r);
1610     if(FAILED(hres))
1611         return hres;
1612
1613     return stack_push(ctx, &v);
1614 }
1615
1616 static HRESULT interp_div(exec_ctx_t *ctx)
1617 {
1618     variant_val_t r, l;
1619     VARIANT v;
1620     HRESULT hres;
1621
1622     TRACE("\n");
1623
1624     hres = stack_pop_val(ctx, &r);
1625     if(FAILED(hres))
1626         return hres;
1627
1628     hres = stack_pop_val(ctx, &l);
1629     if(SUCCEEDED(hres)) {
1630         hres = VarDiv(l.v, r.v, &v);
1631         release_val(&l);
1632     }
1633     release_val(&r);
1634     if(FAILED(hres))
1635         return hres;
1636
1637     return stack_push(ctx, &v);
1638 }
1639
1640 static HRESULT interp_mul(exec_ctx_t *ctx)
1641 {
1642     variant_val_t r, l;
1643     VARIANT v;
1644     HRESULT hres;
1645
1646     TRACE("\n");
1647
1648     hres = stack_pop_val(ctx, &r);
1649     if(FAILED(hres))
1650         return hres;
1651
1652     hres = stack_pop_val(ctx, &l);
1653     if(SUCCEEDED(hres)) {
1654         hres = VarMul(l.v, r.v, &v);
1655         release_val(&l);
1656     }
1657     release_val(&r);
1658     if(FAILED(hres))
1659         return hres;
1660
1661     return stack_push(ctx, &v);
1662 }
1663
1664 static HRESULT interp_exp(exec_ctx_t *ctx)
1665 {
1666     variant_val_t r, l;
1667     VARIANT v;
1668     HRESULT hres;
1669
1670     TRACE("\n");
1671
1672     hres = stack_pop_val(ctx, &r);
1673     if(FAILED(hres))
1674         return hres;
1675
1676     hres = stack_pop_val(ctx, &l);
1677     if(SUCCEEDED(hres)) {
1678         hres = VarPow(l.v, r.v, &v);
1679         release_val(&l);
1680     }
1681     release_val(&r);
1682     if(FAILED(hres))
1683         return hres;
1684
1685     return stack_push(ctx, &v);
1686 }
1687
1688 static HRESULT interp_neg(exec_ctx_t *ctx)
1689 {
1690     variant_val_t val;
1691     VARIANT v;
1692     HRESULT hres;
1693
1694     hres = stack_pop_val(ctx, &val);
1695     if(FAILED(hres))
1696         return hres;
1697
1698     hres = VarNeg(val.v, &v);
1699     release_val(&val);
1700     if(FAILED(hres))
1701         return hres;
1702
1703     return stack_push(ctx, &v);
1704 }
1705
1706 static HRESULT interp_incc(exec_ctx_t *ctx)
1707 {
1708     const BSTR ident = ctx->instr->arg1.bstr;
1709     VARIANT v;
1710     ref_t ref;
1711     HRESULT hres;
1712
1713     TRACE("\n");
1714
1715     hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
1716     if(FAILED(hres))
1717         return hres;
1718
1719     if(ref.type != REF_VAR) {
1720         FIXME("ref.type is not REF_VAR\n");
1721         return E_FAIL;
1722     }
1723
1724     hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v);
1725     if(FAILED(hres))
1726         return hres;
1727
1728     VariantClear(ref.u.v);
1729     *ref.u.v = v;
1730     return S_OK;
1731 }
1732
1733 static const instr_func_t op_funcs[] = {
1734 #define X(x,n,a,b) interp_ ## x,
1735 OP_LIST
1736 #undef X
1737 };
1738
1739 static const unsigned op_move[] = {
1740 #define X(x,n,a,b) n,
1741 OP_LIST
1742 #undef X
1743 };
1744
1745 void release_dynamic_vars(dynamic_var_t *var)
1746 {
1747     while(var) {
1748         VariantClear(&var->v);
1749         var = var->next;
1750     }
1751 }
1752
1753 static void release_exec(exec_ctx_t *ctx)
1754 {
1755     unsigned i;
1756
1757     VariantClear(&ctx->ret_val);
1758     release_dynamic_vars(ctx->dynamic_vars);
1759
1760     if(ctx->this_obj)
1761         IDispatch_Release(ctx->this_obj);
1762
1763     if(ctx->args) {
1764         for(i=0; i < ctx->func->arg_cnt; i++)
1765             VariantClear(ctx->args+i);
1766     }
1767
1768     if(ctx->vars) {
1769         for(i=0; i < ctx->func->var_cnt; i++)
1770             VariantClear(ctx->vars+i);
1771     }
1772
1773     vbsheap_free(&ctx->heap);
1774     heap_free(ctx->args);
1775     heap_free(ctx->vars);
1776     heap_free(ctx->stack);
1777 }
1778
1779 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1780 {
1781     exec_ctx_t exec = {func->code_ctx};
1782     vbsop_t op;
1783     HRESULT hres = S_OK;
1784
1785     exec.code = func->code_ctx;
1786
1787     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1788         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1789         return E_FAIL;
1790     }
1791
1792     vbsheap_init(&exec.heap);
1793
1794     if(func->arg_cnt) {
1795         VARIANT *v;
1796         unsigned i;
1797
1798         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1799         if(!exec.args) {
1800             release_exec(&exec);
1801             return E_OUTOFMEMORY;
1802         }
1803
1804         for(i=0; i < func->arg_cnt; i++) {
1805             v = get_arg(dp, i);
1806             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1807                 if(func->args[i].by_ref)
1808                     exec.args[i] = *v;
1809                 else
1810                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1811             }else {
1812                 hres = VariantCopy(exec.args+i, v);
1813             }
1814             if(FAILED(hres)) {
1815                 release_exec(&exec);
1816                 return hres;
1817             }
1818         }
1819     }else {
1820         exec.args = NULL;
1821     }
1822
1823     if(func->var_cnt) {
1824         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1825         if(!exec.vars) {
1826             release_exec(&exec);
1827             return E_OUTOFMEMORY;
1828         }
1829     }else {
1830         exec.vars = NULL;
1831     }
1832
1833     exec.stack_size = 16;
1834     exec.top = 0;
1835     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1836     if(!exec.stack) {
1837         release_exec(&exec);
1838         return E_OUTOFMEMORY;
1839     }
1840
1841     if(this_obj)
1842         exec.this_obj = this_obj;
1843     else if (ctx->host_global)
1844         exec.this_obj = ctx->host_global;
1845     else
1846         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1847     IDispatch_AddRef(exec.this_obj);
1848
1849     exec.instr = exec.code->instrs + func->code_off;
1850     exec.script = ctx;
1851     exec.func = func;
1852
1853     while(exec.instr) {
1854         op = exec.instr->op;
1855         hres = op_funcs[op](&exec);
1856         if(FAILED(hres)) {
1857             if(exec.resume_next)
1858                 FIXME("Failed %08x in resume next mode\n", hres);
1859             else
1860                 WARN("Failed %08x\n", hres);
1861             stack_popn(&exec, exec.top);
1862             break;
1863         }
1864
1865         exec.instr += op_move[op];
1866     }
1867
1868     assert(!exec.top);
1869     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
1870         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1871
1872     if(SUCCEEDED(hres) && res) {
1873         *res = exec.ret_val;
1874         V_VT(&exec.ret_val) = VT_EMPTY;
1875     }
1876
1877     release_exec(&exec);
1878     return hres;
1879 }