78908: Subject: [PATCH 16/19] vbscript: Added beginning InvokeEx implementation

buildbot at kegel.com buildbot at kegel.com
Thu Sep 15 10:44:04 CDT 2011


This is an experimental automated build and test service.
Please feel free to ignore this email while we work the kinks out.

For more info about this message, see http://wiki.winehq.org/BuildBot

The Buildbot has detected a failed build on builder runtests-heaptest while building Wine.
Full details are available at: http://buildbot.kegel.com/builders/runtests-heaptest/builds/95 (though maybe not for long, as I'm still reinstalling the buildbot periodically while experimenting)
BUILD FAILED: failed shell_3

Errors:
make: *** [run.ok] Error 5

-------------- next part --------------
From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 01/19] vbscript: Added class parser implementation
Message-Id: <4E71ECAF.6080705 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:16:47 +0200

---
  dlls/vbscript/parse.h        |    6 ++++++
  dlls/vbscript/parser.y       |   32 +++++++++++++++++++++++++++++++-
  dlls/vbscript/tests/lang.vbs |    3 +++
  3 files changed, 40 insertions(+), 1 deletions(-)

diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 7e1124c..67fa221 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -142,6 +142,11 @@ typedef struct _function_statement_t {
     function_decl_t *func_decl;
 } function_statement_t;
 
+typedef struct _class_decl_t {
+    const WCHAR *name;
+    struct _class_decl_t *next;
+} class_decl_t;
+
 typedef struct _elseif_decl_t {
     expression_t *expr;
     statement_t *stat;
@@ -170,6 +175,7 @@ typedef struct {
 
     statement_t *stats;
     statement_t *stats_tail;
+    class_decl_t *class_decls;
 
     vbsheap_t heap;
 } parser_ctx_t;
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index a6281d6..6d8a674 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -34,6 +34,7 @@ static int parser_error(const char*);
  static void parse_complete(parser_ctx_t*,BOOL);
 
 static void source_add_statement(parser_ctx_t*,statement_t*);
+static void source_add_class(parser_ctx_t*,class_decl_t*);
 
 static void *new_expression(parser_ctx_t*,expression_type_t,size_t);
 static expression_t *new_bool_expression(parser_ctx_t*,VARIANT_BOOL);
@@ -56,6 +57,7 @@ static dim_decl_t *new_dim_decl(parser_ctx_t*,const WCHAR*,dim_decl_t*);
 static elseif_decl_t *new_elseif_decl(parser_ctx_t*,expression_t*,statement_t*);
 static function_decl_t *new_function_decl(parser_ctx_t*,const WCHAR*,function_type_t,arg_decl_t*,statement_t*);
 static arg_decl_t *new_argument_decl(parser_ctx_t*,const WCHAR*,BOOL);
+static class_decl_t *new_class_decl(parser_ctx_t*);
 
 #define CHECK_ERROR if(((parser_ctx_t*)ctx)->hres != S_OK) YYABORT
 
@@ -73,6 +75,7 @@ static arg_decl_t *new_argument_decl(parser_ctx_t*,const WCHAR*,BOOL);
     dim_decl_t *dim_decl;
     function_decl_t *func_decl;
     arg_decl_t *arg_decl;
+    class_decl_t *class_decl;
     LONG lng;
     BOOL bool;
     double dbl;
@@ -105,6 +108,7 @@ static arg_decl_t *new_argument_decl(parser_ctx_t*,const WCHAR*,BOOL);
 %type <arg_decl> ArgumentsDecl_opt ArgumentDeclList ArgumentDecl
 %type <func_decl> FunctionDecl
 %type <elseif> ElseIfs_opt ElseIfs ElseIf
+%type <class_decl> ClassDeclaration ClassBody
 %type <dim_decl> DimDeclList
 
 %%
@@ -118,7 +122,8 @@ OptionExplicit_opt
 
 SourceElements
     : /* empty */
-    | SourceElements StatementNl    { source_add_statement(ctx, $2); }
+    | SourceElements StatementNl            { source_add_statement(ctx, $2); }
+    | SourceElements ClassDeclaration       { source_add_class(ctx, $2); }
 
 StatementsNl_opt
     : /* empty */                           { $$ = NULL; }
@@ -268,6 +273,12 @@ LiteralExpression
 PrimaryExpression
     : '(' Expression ')'            { $$ = $2; }
 
+ClassDeclaration
+    : tCLASS tIdentifier tNL ClassBody tEND tCLASS tNL      { $4->name = $2; $$ = $4; }
+
+ClassBody
+    : /* empty */                               { $$ = new_class_decl(ctx); }
+
 FunctionDecl
     : /* Storage_opt */ tSUB tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tSUB
                                     { $$ = new_function_decl(ctx, $2, FUNC_SUB, $3, $5); CHECK_ERROR; }
@@ -304,6 +315,12 @@ static void source_add_statement(parser_ctx_t *ctx, statement_t *stat)
     }
 }
 
+static void source_add_class(parser_ctx_t *ctx, class_decl_t *class_decl)
+{
+    class_decl->next = ctx->class_decls;
+    ctx->class_decls = class_decl;
+}
+
 static void parse_complete(parser_ctx_t *ctx, BOOL option_explicit)
 {
     ctx->parse_complete = TRUE;
@@ -545,6 +562,18 @@ static statement_t *new_function_statement(parser_ctx_t *ctx, function_decl_t *d
     return &stat->stat;
 }
 
+static class_decl_t *new_class_decl(parser_ctx_t *ctx)
+{
+    class_decl_t *class_decl;
+
+    class_decl = parser_alloc(ctx, sizeof(*class_decl));
+    if(!class_decl)
+        return NULL;
+
+    class_decl->next = NULL;
+    return class_decl;
+}
+
 void *parser_alloc(parser_ctx_t *ctx, size_t size)
 {
     void *ret;
@@ -568,6 +597,7 @@ HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code)
     ctx->last_token = tNL;
     ctx->last_nl = 0;
     ctx->stats = ctx->stats_tail = NULL;
+    ctx->class_decls = NULL;
     ctx->option_explicit = FALSE;
 
     parser_parse(ctx);
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index b9b5c57..a338e76 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -355,4 +355,7 @@ x = false
 ok SetVal(x, true), "SetVal returned false?"
 Call ok(x, "x is not set to true by SetVal?")
 
+Class EmptyClass
+End Class
+
 reportSuccess()

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 02/19] vbscript: Added class compiler implementation
Message-Id: <4E71ECCD.3010208 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:17:17 +0200

---
  dlls/vbscript/compile.c  |   75 
++++++++++++++++++++++++++++++++++++++++++++++
  dlls/vbscript/vbscript.h |    7 ++++
  2 files changed, 82 insertions(+), 0 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index f74f5fe..21c8588 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -47,6 +47,8 @@ typedef struct {
     function_t *func;
     function_t *funcs;
     function_decl_t *func_decls;
+
+    class_desc_t *classes;
 } compile_ctx_t;
 
 static HRESULT compile_expression(compile_ctx_t*,expression_t*);
@@ -779,8 +781,44 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi
     return S_OK;
 }
 
+static BOOL lookup_class_name(compile_ctx_t *ctx, const WCHAR *name)
+{
+    class_desc_t *iter;
+
+    for(iter = ctx->classes; iter; iter = iter->next) {
+        if(!strcmpiW(iter->name, name))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
+{
+    class_desc_t *class_desc;
+
+    if(lookup_dim_decls(ctx, class_decl->name) || lookup_funcs_name(ctx, class_decl->name)
+            || lookup_class_name(ctx, class_decl->name)) {
+        FIXME("%s: redefinition\n", debugstr_w(class_decl->name));
+        return E_FAIL;
+    }
+
+    class_desc = compiler_alloc(ctx->code, sizeof(*class_desc));
+    if(!class_desc)
+        return E_OUTOFMEMORY;
+
+    class_desc->name = compiler_alloc_string(ctx->code, class_decl->name);
+    if(!class_desc->name)
+        return E_OUTOFMEMORY;
+
+    class_desc->next = ctx->classes;
+    ctx->classes = class_desc;
+    return S_OK;
+}
+
 static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifier)
 {
+    class_desc_t *class;
     dynamic_var_t *var;
     function_t *func;
 
@@ -794,11 +832,17 @@ static BOOL lookup_script_identifier(script_ctx_t *script, const WCHAR *identifi
             return TRUE;
     }
 
+    for(class = script->classes; class; class = class->next) {
+        if(!strcmpiW(class->name, identifier))
+            return TRUE;
+    }
+
     return FALSE;
 }
 
 static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script)
 {
+    class_desc_t *class;
     dynamic_var_t *var;
     function_t *func;
 
@@ -816,6 +860,13 @@ static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script)
         }
     }
 
+    for(class = ctx->classes; class; class = class->next) {
+        if(lookup_script_identifier(script, class->name)) {
+            FIXME("%s: redefined\n", debugstr_w(class->name));
+            return E_FAIL;
+        }
+    }
+
     return S_OK;
 }
 
@@ -891,6 +942,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
 {
     function_t *new_func;
     function_decl_t *func_decl;
+    class_decl_t *class_decl;
     compile_ctx_t ctx;
     vbscode_t *code;
     HRESULT hres;
@@ -907,6 +959,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
     ctx.func_decls = NULL;
     ctx.global_vars = NULL;
     ctx.dim_decls = NULL;
+    ctx.classes = NULL;
     ctx.labels = NULL;
     ctx.labels_cnt = ctx.labels_size = 0;
 
@@ -927,6 +980,14 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
         ctx.funcs = new_func;
     }
 
+    for(class_decl = ctx.parser.class_decls; class_decl; class_decl = class_decl->next) {
+        hres = compile_class(&ctx, class_decl);
+        if(FAILED(hres)) {
+            release_compiler(&ctx);
+            return hres;
+        }
+    }
+
     hres = check_script_collisions(&ctx, script);
     if(FAILED(hres)) {
         release_compiler(&ctx);
@@ -949,6 +1010,20 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, vbscode_t **ret)
         script->global_funcs = ctx.funcs;
     }
 
+    if(ctx.classes) {
+        class_desc_t *class = ctx.classes;
+
+        while(1) {
+            class->ctx = script;
+            if(!class->next)
+                break;
+            class = class->next;
+        }
+
+        class->next = script->classes;
+        script->classes = ctx.classes;
+    }
+
     if(TRACE_ON(vbscript_disas))
         dump_code(&ctx);
 
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 5f1d6ce..9ad3bb6 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -55,6 +55,12 @@ typedef struct named_item_t {
     struct list entry;
 } named_item_t;
 
+typedef struct _class_desc_t {
+    const WCHAR *name;
+    script_ctx_t *ctx;
+    struct _class_desc_t *next;
+} class_desc_t;
+
 typedef struct {
     IDispatchEx IDispatchEx_iface;
 
@@ -98,6 +104,7 @@ struct _script_ctx_t {
 
     dynamic_var_t *global_vars;
     function_t *global_funcs;
+    class_desc_t *classes;
 
     struct list code_list;
     struct list named_items;

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 03/19] vbscript: Added set statement parser/compiler implementation
Message-Id: <4E71ECE2.8050309 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:17:38 +0200

---
  dlls/vbscript/compile.c  |   11 +++++++----
  dlls/vbscript/interp.c   |   14 ++++++++++++++
  dlls/vbscript/parse.h    |    3 ++-
  dlls/vbscript/parser.y   |   16 ++++++++++++++++
  dlls/vbscript/vbscript.h |    2 ++
  5 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 21c8588..d1720cf 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -475,7 +475,7 @@ static HRESULT compile_if_statement(compile_ctx_t *ctx, if_statement_t *stat)
     return S_OK;
 }
 
-static HRESULT compile_assign_statement(compile_ctx_t *ctx, assign_statement_t *stat)
+static HRESULT compile_assign_statement(compile_ctx_t *ctx, assign_statement_t *stat, BOOL is_set)
 {
     HRESULT hres;
 
@@ -493,9 +493,9 @@ static HRESULT compile_assign_statement(compile_ctx_t *ctx, assign_statement_t *
         if(FAILED(hres))
             return hres;
 
-        hres = push_instr_bstr(ctx, OP_assign_member, stat->member_expr->identifier);
+        hres = push_instr_bstr(ctx, is_set ? OP_set_member : OP_assign_member, stat->member_expr->identifier);
     }else {
-        hres = push_instr_bstr(ctx, OP_assign_ident, stat->member_expr->identifier);
+        hres = push_instr_bstr(ctx, is_set ? OP_set_ident : OP_assign_ident, stat->member_expr->identifier);
     }
 
     return hres;
@@ -585,7 +585,7 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
     while(stat) {
         switch(stat->type) {
         case STAT_ASSIGN:
-            hres = compile_assign_statement(ctx, (assign_statement_t*)stat);
+            hres = compile_assign_statement(ctx, (assign_statement_t*)stat, FALSE);
             break;
         case STAT_CALL:
             hres = compile_member_expression(ctx, ((call_statement_t*)stat)->expr, FALSE);
@@ -605,6 +605,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_t *stat)
         case STAT_IF:
             hres = compile_if_statement(ctx, (if_statement_t*)stat);
             break;
+        case STAT_SET:
+            hres = compile_assign_statement(ctx, (assign_statement_t*)stat, TRUE);
+            break;
         default:
             FIXME("Unimplemented statement type %d\n", stat->type);
             hres = E_NOTIMPL;
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 2a50667..e61ed7a 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -385,6 +385,13 @@ static HRESULT interp_assign_ident(exec_ctx_t *ctx)
     return assign_ident(ctx, arg, v.v, v.owned);
 }
 
+static HRESULT interp_set_ident(exec_ctx_t *ctx)
+{
+    const BSTR arg = ctx->instr->arg1.bstr;
+    FIXME("%s\n", debugstr_w(arg));
+    return E_NOTIMPL;
+}
+
 static HRESULT interp_assign_member(exec_ctx_t *ctx)
 {
     BSTR identifier = ctx->instr->arg1.bstr;
@@ -419,6 +426,13 @@ static HRESULT interp_assign_member(exec_ctx_t *ctx)
     return hres;
 }
 
+static HRESULT interp_set_member(exec_ctx_t *ctx)
+{
+    BSTR identifier = ctx->instr->arg1.bstr;
+    FIXME("%s\n", debugstr_w(identifier));
+    return E_NOTIMPL;
+}
+
 static HRESULT interp_jmp(exec_ctx_t *ctx)
 {
     const unsigned arg = ctx->instr->arg1.uint;
diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 67fa221..76f8775 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -94,7 +94,8 @@ typedef enum {
     STAT_EXITFUNC,
     STAT_EXITSUB,
     STAT_FUNC,
-    STAT_IF
+    STAT_IF,
+    STAT_SET
 } statement_type_t;
 
 typedef struct _statement_t {
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index 6d8a674..2e0140e 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -49,6 +49,7 @@ static member_expression_t *new_member_expression(parser_ctx_t*,expression_t*,co
 static void *new_statement(parser_ctx_t*,statement_type_t,size_t);
 static statement_t *new_call_statement(parser_ctx_t*,member_expression_t*);
 static statement_t *new_assign_statement(parser_ctx_t*,member_expression_t*,expression_t*);
+static statement_t *new_set_statement(parser_ctx_t*,member_expression_t*,expression_t*);
 static statement_t *new_dim_statement(parser_ctx_t*,dim_decl_t*);
 static statement_t *new_if_statement(parser_ctx_t*,expression_t*,statement_t*,elseif_decl_t*,statement_t*);
 static statement_t *new_function_statement(parser_ctx_t*,function_decl_t*);
@@ -146,6 +147,8 @@ Statement
     | FunctionDecl                          { $$ = new_function_statement(ctx, $1); CHECK_ERROR; }
     | tEXIT tFUNCTION                       { $$ = new_statement(ctx, STAT_EXITFUNC, 0); CHECK_ERROR; }
     | tEXIT tSUB                            { $$ = new_statement(ctx, STAT_EXITSUB, 0); CHECK_ERROR; }
+    | tSET MemberExpression Arguments_opt '=' Expression
+                                            { $2->args = $3; $$ = new_set_statement(ctx, $2, $5); CHECK_ERROR; }
 
 MemberExpression
     : tIdentifier                           { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; }
@@ -465,6 +468,19 @@ static statement_t *new_assign_statement(parser_ctx_t *ctx, member_expression_t
     return &stat->stat;
 }
 
+static statement_t *new_set_statement(parser_ctx_t *ctx, member_expression_t *left, expression_t *right)
+{
+    assign_statement_t *stat;
+
+    stat = new_statement(ctx, STAT_SET, sizeof(*stat));
+    if(!stat)
+        return NULL;
+
+    stat->member_expr = left;
+    stat->value_expr = right;
+    return &stat->stat;
+}
+
 static dim_decl_t *new_dim_decl(parser_ctx_t *ctx, const WCHAR *name, dim_decl_t *next)
 {
     dim_decl_t *decl;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 9ad3bb6..9655978 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -150,6 +150,8 @@ typedef enum {
     X(null,           1, 0,           0)          \
     X(or,             1, 0,           0)          \
     X(ret,            0, 0,           0)          \
+    X(set_ident,      1, ARG_BSTR,    0)          \
+    X(set_member,     1, ARG_BSTR,    0)          \
     X(short,          1, ARG_INT,     0)          \
     X(string,         1, ARG_STR,     0)          \
     X(sub,            1, 0,           0)          \

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 04/19] vbscript: Added interp_set_ident implementation
Message-Id: <4E71ECEF.3060006 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:17:51 +0200

---
  dlls/vbscript/interp.c       |   15 +++++++++++++--
  dlls/vbscript/tests/lang.vbs |    3 +++
  2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index e61ed7a..705992c 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -388,8 +388,19 @@ static HRESULT interp_assign_ident(exec_ctx_t *ctx)
 static HRESULT interp_set_ident(exec_ctx_t *ctx)
 {
     const BSTR arg = ctx->instr->arg1.bstr;
-    FIXME("%s\n", debugstr_w(arg));
-    return E_NOTIMPL;
+    IDispatch *disp;
+    VARIANT v;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_w(arg));
+
+    hres = stack_pop_disp(ctx, &disp);
+    if(FAILED(hres))
+        return hres;
+
+    V_VT(&v) = VT_DISPATCH;
+    V_DISPATCH(&v) = disp;
+    return assign_ident(ctx, ctx->instr->arg1.bstr, &v, TRUE);
 }
 
 static HRESULT interp_assign_member(exec_ctx_t *ctx)
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index a338e76..01c7072 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -355,6 +355,9 @@ x = false
 ok SetVal(x, true), "SetVal returned false?"
 Call ok(x, "x is not set to true by SetVal?")
 
+set x = testObj
+Call ok(getVT(x) = "VT_DISPATCH*", "getVT(x=testObj) = " & getVT(x))
+
 Class EmptyClass
 End Class
 

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 05/19] vbscript: Added new expression parser/compiler implemetation
Message-Id: <4E71ED04.6070901 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:18:12 +0200

---
  dlls/vbscript/compile.c  |    2 ++
  dlls/vbscript/interp.c   |    7 +++++++
  dlls/vbscript/parse.h    |    1 +
  dlls/vbscript/parser.y   |   14 ++++++++++++++
  dlls/vbscript/vbscript.h |    1 +
  5 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index d1720cf..b9e05bd9 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -390,6 +390,8 @@ static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr)
         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_neg);
     case EXPR_NEQUAL:
         return compile_binary_expression(ctx, (binary_expression_t*)expr, OP_nequal);
+    case EXPR_NEW:
+        return push_instr_str(ctx, OP_new, ((string_expression_t*)expr)->value);
     case EXPR_NOT:
         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_not);
     case EXPR_NULL:
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 705992c..dd4f4ff 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -444,6 +444,13 @@ static HRESULT interp_set_member(exec_ctx_t *ctx)
     return E_NOTIMPL;
 }
 
+static HRESULT interp_new(exec_ctx_t *ctx)
+{
+    const WCHAR *arg = ctx->instr->arg1.bstr;
+    FIXME("%s\n", debugstr_w(arg));
+    return E_NOTIMPL;
+}
+
 static HRESULT interp_jmp(exec_ctx_t *ctx)
 {
     const unsigned arg = ctx->instr->arg1.uint;
diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 76f8775..21f0d60 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -34,6 +34,7 @@ typedef enum {
     EXPR_MUL,
     EXPR_NEG,
     EXPR_NEQUAL,
+    EXPR_NEW,
     EXPR_NOT,
     EXPR_NULL,
     EXPR_OR,
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index 2e0140e..48a5ab4 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -43,6 +43,7 @@ static expression_t *new_long_expression(parser_ctx_t*,expression_type_t,LONG);
 static expression_t *new_double_expression(parser_ctx_t*,double);
 static expression_t *new_unary_expression(parser_ctx_t*,expression_type_t,expression_t*);
 static expression_t *new_binary_expression(parser_ctx_t*,expression_type_t,expression_t*,expression_t*);
+static expression_t *new_new_expression(parser_ctx_t*,const WCHAR*);
 
 static member_expression_t *new_member_expression(parser_ctx_t*,expression_t*,const WCHAR*);
 
@@ -256,6 +257,7 @@ ExpExpression
 UnaryExpression
     : LiteralExpression             { $$ = $1; }
     | CallExpression                { $$ = $1; }
+    | tNEW tIdentifier              { $$ = new_new_expression(ctx, $2); CHECK_ERROR; }
     | '-' UnaryExpression           { $$ = new_unary_expression(ctx, EXPR_NEG, $2); CHECK_ERROR; }
 
 CallExpression
@@ -430,6 +432,18 @@ static member_expression_t *new_member_expression(parser_ctx_t *ctx, expression_
     return expr;
 }
 
+static expression_t *new_new_expression(parser_ctx_t *ctx, const WCHAR *identifier)
+{
+    string_expression_t *expr;
+
+    expr = new_expression(ctx, EXPR_NEW, sizeof(*expr));
+    if(!expr)
+        return NULL;
+
+    expr->value = identifier;
+    return &expr->expr;
+}
+
 static void *new_statement(parser_ctx_t *ctx, statement_type_t type, size_t size)
 {
     statement_t *stat;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 9655978..3e3af5b 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -146,6 +146,7 @@ typedef enum {
     X(mul,            1, 0,           0)          \
     X(neg,            1, 0,           0)          \
     X(nequal,         1, 0,           0)          \
+    X(new,            1, ARG_STR,     0)          \
     X(not,            1, 0,           0)          \
     X(null,           1, 0,           0)          \
     X(or,             1, 0,           0)          \

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 06/19] vbscript: Added interp_new implementation
Message-Id: <4E71ED15.5030105 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:18:29 +0200

---
  dlls/vbscript/interp.c       |   25 +++++++++++++++++++++++--
  dlls/vbscript/tests/lang.vbs |    4 ++++
  dlls/vbscript/vbdisp.c       |    2 +-
  dlls/vbscript/vbscript.h     |    1 +
  4 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index dd4f4ff..04ed81d 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -447,8 +447,29 @@ static HRESULT interp_set_member(exec_ctx_t *ctx)
 static HRESULT interp_new(exec_ctx_t *ctx)
 {
     const WCHAR *arg = ctx->instr->arg1.bstr;
-    FIXME("%s\n", debugstr_w(arg));
-    return E_NOTIMPL;
+    class_desc_t *class_desc;
+    vbdisp_t *obj;
+    VARIANT v;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_w(arg));
+
+    for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
+        if(!strcmpiW(class_desc->name, arg))
+            break;
+    }
+    if(!class_desc) {
+        FIXME("Class %s not found\n", debugstr_w(arg));
+        return E_FAIL;
+    }
+
+    hres = create_vbdisp(&obj);
+    if(FAILED(hres))
+        return hres;
+
+    V_VT(&v) = VT_DISPATCH;
+    V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
+    return stack_push(ctx, &v);
 }
 
 static HRESULT interp_jmp(exec_ctx_t *ctx)
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 01c7072..c89009b 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -358,6 +358,10 @@ Call ok(x, "x is not set to true by SetVal?")
 set x = testObj
 Call ok(getVT(x) = "VT_DISPATCH*", "getVT(x=testObj) = " & getVT(x))
 
+Dim obj
+Set obj = New EmptyClass
+Call ok(getVT(obj) = "VT_DISPATCH*", "getVT(obj) = " & getVT(obj))
+
 Class EmptyClass
 End Class
 
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index 9cfdab2..73006be 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -184,7 +184,7 @@ static IDispatchExVtbl DispatchExVtbl = {
     DispatchEx_GetNameSpaceParent
 };
 
-static HRESULT create_vbdisp(vbdisp_t **ret)
+HRESULT create_vbdisp(vbdisp_t **ret)
 {
     vbdisp_t *vbdisp;
 
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 3e3af5b..9e77714 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -74,6 +74,7 @@ typedef enum {
     VBDISP_ANY
 } vbdisp_invoke_type_t;
 
+HRESULT create_vbdisp(vbdisp_t**);
 HRESULT disp_get_id(IDispatch*,BSTR,DISPID*);
 HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,DISPPARAMS*,VARIANT*);
 HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,VARIANT*);

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 07/19] vbscript: Store class_desc_t in vbdisp_t
Message-Id: <4E71ED23.2030409 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:18:43 +0200

---
  dlls/vbscript/interp.c   |    2 +-
  dlls/vbscript/vbdisp.c   |    6 ++++--
  dlls/vbscript/vbscript.h |    5 ++++-
  3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 04ed81d..b413243 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -463,7 +463,7 @@ static HRESULT interp_new(exec_ctx_t *ctx)
         return E_FAIL;
     }
 
-    hres = create_vbdisp(&obj);
+    hres = create_vbdisp(class_desc, &obj);
     if(FAILED(hres))
         return hres;
 
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index 73006be..f1a323d 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -184,7 +184,7 @@ static IDispatchExVtbl DispatchExVtbl = {
     DispatchEx_GetNameSpaceParent
 };
 
-HRESULT create_vbdisp(vbdisp_t **ret)
+HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
 {
     vbdisp_t *vbdisp;
 
@@ -194,6 +194,7 @@ HRESULT create_vbdisp(vbdisp_t **ret)
 
     vbdisp->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
     vbdisp->ref = 1;
+    vbdisp->desc = desc;
 
     *ret = vbdisp;
     return S_OK;
@@ -201,7 +202,8 @@ HRESULT create_vbdisp(vbdisp_t **ret)
 
 HRESULT init_global(script_ctx_t *ctx)
 {
-    return create_vbdisp(&ctx->script_obj);
+    ctx->script_desc.ctx = ctx;
+    return create_vbdisp(&ctx->script_desc, &ctx->script_obj);
 }
 
 HRESULT disp_get_id(IDispatch *disp, BSTR name, DISPID *id)
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 9e77714..dabf52b 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -65,6 +65,8 @@ typedef struct {
     IDispatchEx IDispatchEx_iface;
 
     LONG ref;
+
+    const class_desc_t *desc;
 } vbdisp_t;
 
 typedef enum {
@@ -74,7 +76,7 @@ typedef enum {
     VBDISP_ANY
 } vbdisp_invoke_type_t;
 
-HRESULT create_vbdisp(vbdisp_t**);
+HRESULT create_vbdisp(const class_desc_t*,vbdisp_t**);
 HRESULT disp_get_id(IDispatch*,BSTR,DISPID*);
 HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,DISPPARAMS*,VARIANT*);
 HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,VARIANT*);
@@ -101,6 +103,7 @@ struct _script_ctx_t {
 
     IDispatch *host_global;
 
+    class_desc_t script_desc;
     vbdisp_t *script_obj;
 
     dynamic_var_t *global_vars;

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 08/19] vbscript: Added nothing literal parser/compiler implementation
Message-Id: <4E71ED30.7030304 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:18:56 +0200

---
  dlls/vbscript/compile.c  |    2 ++
  dlls/vbscript/interp.c   |    6 ++++++
  dlls/vbscript/parse.h    |    1 +
  dlls/vbscript/parser.y   |    1 +
  dlls/vbscript/vbscript.h |    1 +
  5 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index b9e05bd9..36bf04c 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -394,6 +394,8 @@ static HRESULT compile_expression(compile_ctx_t *ctx, expression_t *expr)
         return push_instr_str(ctx, OP_new, ((string_expression_t*)expr)->value);
     case EXPR_NOT:
         return compile_unary_expression(ctx, (unary_expression_t*)expr, OP_not);
+    case EXPR_NOTHING:
+        return push_instr(ctx, OP_nothing) != -1 ? S_OK : E_OUTOFMEMORY;
     case EXPR_NULL:
         return push_instr(ctx, OP_null) != -1 ? S_OK : E_OUTOFMEMORY;
     case EXPR_OR:
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index b413243..4094ac1 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -597,6 +597,12 @@ static HRESULT interp_null(exec_ctx_t *ctx)
     return stack_push(ctx, &v);
 }
 
+static HRESULT interp_nothing(exec_ctx_t *ctx)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
 static HRESULT interp_not(exec_ctx_t *ctx)
 {
     variant_val_t val;
diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 21f0d60..ac0f310 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -36,6 +36,7 @@ typedef enum {
     EXPR_NEQUAL,
     EXPR_NEW,
     EXPR_NOT,
+    EXPR_NOTHING,
     EXPR_NULL,
     EXPR_OR,
     EXPR_STRING,
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index 48a5ab4..50a4bf1 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -274,6 +274,7 @@ LiteralExpression
     | tDouble                       { $$ = new_double_expression(ctx, $1); CHECK_ERROR; }
     | tEMPTY                        { $$ = new_expression(ctx, EXPR_EMPTY, 0); CHECK_ERROR; }
     | tNULL                         { $$ = new_expression(ctx, EXPR_NULL, 0); CHECK_ERROR; }
+    | tNOTHING                      { $$ = new_expression(ctx, EXPR_NOTHING, 0); CHECK_ERROR; }
 
 PrimaryExpression
     : '(' Expression ')'            { $$ = $2; }
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index dabf52b..4c2d977 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -152,6 +152,7 @@ typedef enum {
     X(nequal,         1, 0,           0)          \
     X(new,            1, ARG_STR,     0)          \
     X(not,            1, 0,           0)          \
+    X(nothing,        1, 0,           0)          \
     X(null,           1, 0,           0)          \
     X(or,             1, 0,           0)          \
     X(ret,            0, 0,           0)          \

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 09/19] vbscript: Added interp_nothing implementation and tests
Message-Id: <4E71ED47.2040102 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:19:19 +0200

---
  dlls/vbscript/interp.c       |    9 +++++++--
  dlls/vbscript/tests/lang.vbs |    5 +++++
  dlls/vbscript/tests/run.c    |   29 +++++++++++++++++++++++++++++
  3 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 4094ac1..f8e0011 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -599,8 +599,13 @@ static HRESULT interp_null(exec_ctx_t *ctx)
 
 static HRESULT interp_nothing(exec_ctx_t *ctx)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    VARIANT v;
+
+    TRACE("\n");
+
+    V_VT(&v) = VT_DISPATCH;
+    V_DISPATCH(&v) = NULL;
+    return stack_push(ctx, &v);
 }
 
 static HRESULT interp_not(exec_ctx_t *ctx)
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index c89009b..a94b2cd 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -71,9 +71,14 @@ Call ok(getVT(1 & 100000) = "VT_BSTR", "getVT(1 & 100000) is not VT_BSTR")
 Call ok(getVT(-empty) = "VT_I2", "getVT(-empty) = " & getVT(-empty))
 Call ok(getVT(-null) = "VT_NULL", "getVT(-null) = " & getVT(-null))
 Call ok(getVT(y) = "VT_EMPTY*", "getVT(y) = " & getVT(y))
+Call ok(getVT(nothing) = "VT_DISPATCH", "getVT(nothing) = " & getVT(nothing))
+set x = nothing
+Call ok(getVT(x) = "VT_DISPATCH*", "getVT(x=nothing) = " & getVT(x))
 x = true
 Call ok(getVT(x) = "VT_BOOL*", "getVT(x) = " & getVT(x))
 
+Call ok(isNullDisp(nothing), "nothing is not nulldisp?")
+
 x = "xx"
 Call ok("ab" & "cd" = "abcd", """ab"" & ""cd"" <> ""abcd""")
 Call ok("ab " & null = "ab ", """ab"" & null = " & ("ab " & null))
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c
index aa2e3f1..4281b16 100644
--- a/dlls/vbscript/tests/run.c
+++ b/dlls/vbscript/tests/run.c
@@ -70,6 +70,7 @@ DEFINE_EXPECT(testobj_propput_i);
 #define DISPID_GLOBAL_ISENGLOC      1004
 #define DISPID_GLOBAL_VBVAR         1005
 #define DISPID_GLOBAL_TESTOBJ       1006
+#define DISPID_GLOBAL_ISNULLDISP    1007
 
 #define DISPID_TESTOBJ_PROPPUT      2001
 
@@ -329,6 +330,12 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
         *pid = DISPID_GLOBAL_VBVAR;
         return S_OK;
     }
+    if(!strcmp_wa(bstrName, "isNullDisp")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_ISNULLDISP;
+        return S_OK;
+    }
+
 
     if(strict_dispid_check && strcmp_wa(bstrName, "x"))
         ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
@@ -459,6 +466,28 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
         V_VT(pvarRes) = VT_DISPATCH;
         V_DISPATCH(pvarRes) = (IDispatch*)&testObj;
         return S_OK;
+
+    case DISPID_GLOBAL_ISNULLDISP: {
+        VARIANT *v;
+
+        ok(wFlags == (INVOKE_FUNC|INVOKE_PROPERTYGET), "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
+        ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pvarRes != NULL, "pvarRes == NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        v = pdp->rgvarg;
+        if(V_VT(v) == (VT_VARIANT|VT_BYREF))
+            v = V_VARIANTREF(v);
+
+        ok(V_VT(v) == VT_DISPATCH, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
+        V_VT(pvarRes) = VT_BOOL;
+        V_BOOL(pvarRes) = V_DISPATCH(v) ? VARIANT_FALSE : VARIANT_TRUE;
+        return S_OK;
+    }
     }
 
     ok(0, "unexpected call %d\n", id);

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 10/19] vbscript: Added object member call implementation
Message-Id: <4E71ED5D.6030704 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:19:41 +0200

---
  dlls/vbscript/compile.c  |    7 ++++-
  dlls/vbscript/interp.c   |   51 
++++++++++++++++++++++++++++++++++++++++++++++
  dlls/vbscript/vbscript.h |    2 +
  3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 36bf04c..698ea8d 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -318,8 +318,11 @@ static HRESULT compile_member_expression(compile_ctx_t *ctx, member_expression_t
         return hres;
 
     if(expr->obj_expr) {
-        FIXME("obj_expr not implemented\n");
-        hres = E_NOTIMPL;
+        hres = compile_expression(ctx, expr->obj_expr);
+        if(FAILED(hres))
+            return hres;
+
+        hres = push_instr_bstr_uint(ctx, ret_val ? OP_mcall : OP_mcallv, expr->identifier, arg_cnt);
     }else {
         hres = push_instr_bstr_uint(ctx, ret_val ? OP_icall : OP_icallv, expr->identifier, arg_cnt);
     }
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index f8e0011..beacfe9 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -327,6 +327,57 @@ static HRESULT interp_icallv(exec_ctx_t *ctx)
     return do_icall(ctx, NULL);
 }
 
+static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
+{
+    const BSTR identifier = ctx->instr->arg1.bstr;
+    const unsigned arg_cnt = ctx->instr->arg2.uint;
+    IDispatch *obj;
+    DISPPARAMS dp;
+    DISPID id;
+    HRESULT hres;
+
+    hres = stack_pop_disp(ctx, &obj);
+    if(FAILED(hres))
+        return hres;
+
+    if(!obj) {
+        FIXME("NULL obj\n");
+        return E_FAIL;
+    }
+
+    vbstack_to_dp(ctx, arg_cnt, &dp);
+
+    hres = disp_get_id(obj, identifier, &id);
+    if(SUCCEEDED(hres))
+        hres = disp_call(ctx->script, obj, id, &dp, res);
+    IDispatch_Release(obj);
+    if(FAILED(hres))
+        return hres;
+
+    stack_popn(ctx, arg_cnt);
+    return S_OK;
+}
+
+static HRESULT interp_mcall(exec_ctx_t *ctx)
+{
+    VARIANT res;
+    HRESULT hres;
+
+    TRACE("\n");
+
+    hres = do_mcall(ctx, &res);
+    if(FAILED(hres))
+        return hres;
+
+    return stack_push(ctx, &res);
+}
+
+static HRESULT interp_mcallv(exec_ctx_t *ctx)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
 {
     ref_t ref;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 4c2d977..8defcd6 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -146,6 +146,8 @@ typedef enum {
     X(jmp,            0, ARG_ADDR,    0)          \
     X(jmp_false,      0, ARG_ADDR,    0)          \
     X(long,           1, ARG_INT,     0)          \
+    X(mcall,          1, ARG_BSTR,    ARG_UINT)   \
+    X(mcallv,         1, ARG_BSTR,    ARG_UINT)   \
     X(mod,            1, 0,           0)          \
     X(mul,            1, 0,           0)          \
     X(neg,            1, 0,           0)          \

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 11/19] vbscript: Added obj member call test
Message-Id: <4E71ED68.9010902 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:19:52 +0200

---
  dlls/vbscript/tests/run.c |   30 ++++++++++++++++++++++++++++++
  1 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c
index 4281b16..fa6eec1 100644
--- a/dlls/vbscript/tests/run.c
+++ b/dlls/vbscript/tests/run.c
@@ -60,6 +60,8 @@ DEFINE_EXPECT(global_success_d);
 DEFINE_EXPECT(global_success_i);
 DEFINE_EXPECT(global_vbvar_d);
 DEFINE_EXPECT(global_vbvar_i);
+DEFINE_EXPECT(testobj_propget_d);
+DEFINE_EXPECT(testobj_propget_i);
 DEFINE_EXPECT(testobj_propput_d);
 DEFINE_EXPECT(testobj_propput_i);
 
@@ -72,6 +74,7 @@ DEFINE_EXPECT(testobj_propput_i);
 #define DISPID_GLOBAL_TESTOBJ       1006
 #define DISPID_GLOBAL_ISNULLDISP    1007
 
+#define DISPID_TESTOBJ_PROPGET      2000
 #define DISPID_TESTOBJ_PROPPUT      2001
 
 static const WCHAR testW[] = {'t','e','s','t',0};
@@ -234,6 +237,12 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown
 
 static HRESULT WINAPI testObj_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
 {
+    if(!strcmp_wa(bstrName, "propget")) {
+        CHECK_EXPECT(testobj_propget_d);
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_TESTOBJ_PROPGET;
+        return S_OK;
+    }
     if(!strcmp_wa(bstrName, "propput")) {
         CHECK_EXPECT(testobj_propput_d);
         test_grfdex(grfdex, fdexNameCaseInsensitive);
@@ -249,6 +258,21 @@ static HRESULT WINAPI testObj_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
 {
     switch(id) {
+    case DISPID_TESTOBJ_PROPGET:
+        CHECK_EXPECT(testobj_propget_i);
+
+        ok(wFlags == (DISPATCH_PROPERTYGET|DISPATCH_METHOD), "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(!pdp->rgvarg, "rgvarg == NULL\n");
+        ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
+        ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pvarRes != NULL, "pvarRes == NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        V_VT(pvarRes) = VT_I2;
+        V_I2(pvarRes) = 10;
+        return S_OK;
     case DISPID_TESTOBJ_PROPPUT:
         CHECK_EXPECT(testobj_propput_i);
 
@@ -802,6 +826,12 @@ static void run_tests(void)
     CHECK_CALLED(global_vbvar_d);
     CHECK_CALLED(global_vbvar_i);
 
+    SET_EXPECT(testobj_propget_d);
+    SET_EXPECT(testobj_propget_i);
+    parse_script_a("dim x\nx = testObj.propget");
+    CHECK_CALLED(testobj_propget_d);
+    CHECK_CALLED(testobj_propget_i);
+
     SET_EXPECT(testobj_propput_d);
     SET_EXPECT(testobj_propput_i);
     parse_script_a("testObj.propput = 1");

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 12/19] vbscript: Added function storage specifiers support
Message-Id: <4E71ED75.6000301 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:20:05 +0200

---
  dlls/vbscript/compile.c      |    1 +
  dlls/vbscript/parse.h        |    1 +
  dlls/vbscript/parser.y       |   35 ++++++++++++++++++++++++++++-------
  dlls/vbscript/tests/lang.vbs |   16 ++++++++++++++++
  dlls/vbscript/vbscript.h     |    1 +
  5 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 698ea8d..5c7f7e3 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -760,6 +760,7 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi
     func->var_cnt = 0;
     func->code_ctx = ctx->code;
     func->type = decl->type;
+    func->is_public = decl->is_public;
 
     func->arg_cnt = 0;
     if(decl->args) {
diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index ac0f310..3a4d03b 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -135,6 +135,7 @@ typedef struct _arg_decl_t {
 typedef struct _function_decl_t {
     const WCHAR *name;
     function_type_t type;
+    BOOL is_public;
     arg_decl_t *args;
     statement_t *body;
     struct _function_decl_t *next;
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index 50a4bf1..e310a70 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -31,7 +31,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
 
 static int parser_error(const char*);
 
- static void parse_complete(parser_ctx_t*,BOOL);
+static void parse_complete(parser_ctx_t*,BOOL);
 
 static void source_add_statement(parser_ctx_t*,statement_t*);
 static void source_add_class(parser_ctx_t*,class_decl_t*);
@@ -57,10 +57,13 @@ static statement_t *new_function_statement(parser_ctx_t*,function_decl_t*);
 
 static dim_decl_t *new_dim_decl(parser_ctx_t*,const WCHAR*,dim_decl_t*);
 static elseif_decl_t *new_elseif_decl(parser_ctx_t*,expression_t*,statement_t*);
-static function_decl_t *new_function_decl(parser_ctx_t*,const WCHAR*,function_type_t,arg_decl_t*,statement_t*);
+static function_decl_t *new_function_decl(parser_ctx_t*,const WCHAR*,function_type_t,unsigned,arg_decl_t*,statement_t*);
 static arg_decl_t *new_argument_decl(parser_ctx_t*,const WCHAR*,BOOL);
 static class_decl_t *new_class_decl(parser_ctx_t*);
 
+#define STORAGE_IS_PRIVATE    1
+#define STORAGE_IS_DEFAULT    2
+
 #define CHECK_ERROR if(((parser_ctx_t*)ctx)->hres != S_OK) YYABORT
 
 %}
@@ -78,6 +81,7 @@ static class_decl_t *new_class_decl(parser_ctx_t*);
     function_decl_t *func_decl;
     arg_decl_t *arg_decl;
     class_decl_t *class_decl;
+    unsigned uint;
     LONG lng;
     BOOL bool;
     double dbl;
@@ -111,6 +115,7 @@ static class_decl_t *new_class_decl(parser_ctx_t*);
 %type <func_decl> FunctionDecl
 %type <elseif> ElseIfs_opt ElseIfs ElseIf
 %type <class_decl> ClassDeclaration ClassBody
+%type <uint> Storage Storage_opt
 %type <dim_decl> DimDeclList
 
 %%
@@ -286,10 +291,19 @@ ClassBody
     : /* empty */                               { $$ = new_class_decl(ctx); }
 
 FunctionDecl
-    : /* Storage_opt */ tSUB tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tSUB
-                                    { $$ = new_function_decl(ctx, $2, FUNC_SUB, $3, $5); CHECK_ERROR; }
-    | /* Storage_opt */ tFUNCTION tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tFUNCTION
-                                    { $$ = new_function_decl(ctx, $2, FUNC_FUNCTION, $3, $5); CHECK_ERROR; }
+    : Storage_opt tSUB tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tSUB
+                                    { $$ = new_function_decl(ctx, $3, FUNC_SUB, $1, $4, $6); CHECK_ERROR; }
+    | Storage_opt tFUNCTION tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tFUNCTION
+                                    { $$ = new_function_decl(ctx, $3, FUNC_FUNCTION, $1, $4, $6); CHECK_ERROR; }
+
+Storage_opt
+    : /* empty*/                    { $$ = 0; }
+    | Storage                       { $$ = $1; }
+
+Storage
+    : tPUBLIC tDEFAULT              { $$ = STORAGE_IS_DEFAULT; }
+    | tPUBLIC                       { $$ = 0; }
+    | tPRIVATE                      { $$ = STORAGE_IS_PRIVATE; }
 
 ArgumentsDecl_opt
     : EmptyBrackets_opt                         { $$ = NULL; }
@@ -566,16 +580,23 @@ static arg_decl_t *new_argument_decl(parser_ctx_t *ctx, const WCHAR *name, BOOL
 }
 
 static function_decl_t *new_function_decl(parser_ctx_t *ctx, const WCHAR *name, function_type_t type,
-        arg_decl_t *arg_decl, statement_t *body)
+        unsigned storage_flags, arg_decl_t *arg_decl, statement_t *body)
 {
     function_decl_t *decl;
 
+    if(storage_flags & STORAGE_IS_DEFAULT) {
+        FIXME("Function declared as default property\n");
+        ctx->hres = E_FAIL;
+        return NULL;
+    }
+
     decl = parser_alloc(ctx, sizeof(*decl));
     if(!decl)
         return NULL;
 
     decl->name = name;
     decl->type = type;
+    decl->is_public = !(storage_flags & STORAGE_IS_PRIVATE);
     decl->args = arg_decl;
     decl->body = body;
     return decl;
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index a94b2cd..bc64f85 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -271,6 +271,14 @@ y = true
 Call TestSubLocalVal
 Call ok(x, "global x is not true?")
 
+Public Sub TestPublicSub
+End Sub
+Call TestPublicSub
+
+Private Sub TestPrivateSub
+End Sub
+Call TestPrivateSub
+
 if false then
 Function testfunc
     x = true
@@ -360,6 +368,14 @@ x = false
 ok SetVal(x, true), "SetVal returned false?"
 Call ok(x, "x is not set to true by SetVal?")
 
+Public Function TestPublicFunc
+End Function
+Call TestPublicFunc
+
+Private Function TestPrivateFunc
+End Function
+Call TestPrivateFunc
+
 set x = testObj
 Call ok(getVT(x) = "VT_DISPATCH*", "getVT(x=testObj) = " & getVT(x))
 
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 8defcd6..014e480 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -204,6 +204,7 @@ typedef struct {
 struct _function_t {
     function_type_t type;
     const WCHAR *name;
+    BOOL is_public;
     arg_desc_t *args;
     unsigned arg_cnt;
     var_desc_t *vars;

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 13/19] vbscript: Added class functions parser implementation
Message-Id: <4E71ED89.40705 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:20:25 +0200

---
  dlls/vbscript/parse.h        |    1 +
  dlls/vbscript/parser.y       |   23 +++++++++++++++++++++++
  dlls/vbscript/tests/lang.vbs |   12 ++++++++++++
  3 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 3a4d03b..94ba0cf 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -148,6 +148,7 @@ typedef struct _function_statement_t {
 
 typedef struct _class_decl_t {
     const WCHAR *name;
+    function_decl_t *funcs;
     struct _class_decl_t *next;
 } class_decl_t;
 
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index e310a70..ed7cc67 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -59,7 +59,9 @@ static dim_decl_t *new_dim_decl(parser_ctx_t*,const WCHAR*,dim_decl_t*);
 static elseif_decl_t *new_elseif_decl(parser_ctx_t*,expression_t*,statement_t*);
 static function_decl_t *new_function_decl(parser_ctx_t*,const WCHAR*,function_type_t,unsigned,arg_decl_t*,statement_t*);
 static arg_decl_t *new_argument_decl(parser_ctx_t*,const WCHAR*,BOOL);
+
 static class_decl_t *new_class_decl(parser_ctx_t*);
+static class_decl_t *add_class_function(parser_ctx_t*,class_decl_t*,function_decl_t*);
 
 #define STORAGE_IS_PRIVATE    1
 #define STORAGE_IS_DEFAULT    2
@@ -289,6 +291,7 @@ ClassDeclaration
 
 ClassBody
     : /* empty */                               { $$ = new_class_decl(ctx); }
+    | FunctionDecl tNL ClassBody                { $$ = add_class_function(ctx, $3, $1); CHECK_ERROR; }
 
 FunctionDecl
     : Storage_opt tSUB tIdentifier ArgumentsDecl_opt tNL StatementsNl_opt tEND tSUB
@@ -599,6 +602,7 @@ static function_decl_t *new_function_decl(parser_ctx_t *ctx, const WCHAR *name,
     decl->is_public = !(storage_flags & STORAGE_IS_PRIVATE);
     decl->args = arg_decl;
     decl->body = body;
+    decl->next = NULL;
     return decl;
 }
 
@@ -626,6 +630,25 @@ static class_decl_t *new_class_decl(parser_ctx_t *ctx)
     return class_decl;
 }
 
+static class_decl_t *add_class_function(parser_ctx_t *ctx, class_decl_t *class_decl, function_decl_t *decl)
+{
+    function_decl_t *iter;
+
+    for(iter = class_decl->funcs; iter; iter = iter->next) {
+        if(!strcmpiW(iter->name, decl->name)) {
+            if(decl->type == FUNC_SUB || decl->type == FUNC_FUNCTION) {
+                FIXME("Redefinition of %s::%s\n", debugstr_w(class_decl->name), debugstr_w(decl->name));
+                ctx->hres = E_FAIL;
+                return NULL;
+            }
+        }
+    }
+
+    decl->next = class_decl->funcs;
+    class_decl->funcs = decl;
+    return class_decl;
+}
+
 void *parser_alloc(parser_ctx_t *ctx, size_t size)
 {
     void *ret;
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index bc64f85..2f78403 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -386,4 +386,16 @@ Call ok(getVT(obj) = "VT_DISPATCH*", "getVT(obj) = " & getVT(obj))
 Class EmptyClass
 End Class
 
+Class TestClass
+    Public Function publicFunction()
+        publicFunction = 4
+    End Function
+
+    Public Sub publicSub
+    End Sub
+
+    Public Sub privateSub
+    End Sub
+End Class
+
 reportSuccess()

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 14/19] vbscript: Added class function compiler implementation
Message-Id: <4E71ED9E.808 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:20:46 +0200

---
  dlls/vbscript/compile.c  |   33 +++++++++++++++++++++++++++++++++
  dlls/vbscript/vbscript.h |   22 +++++++++++++++-------
  2 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index 5c7f7e3..32707dc 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -804,9 +804,26 @@ static BOOL lookup_class_name(compile_ctx_t *ctx, const WCHAR *name)
     return FALSE;
 }
 
+static HRESULT create_class_funcprop(compile_ctx_t *ctx, function_decl_t *func_decl, vbdisp_funcprop_desc_t *desc)
+{
+    desc->name = compiler_alloc_string(ctx->code, func_decl->name);
+    if(!desc->name)
+        return E_OUTOFMEMORY;
+
+    assert(!desc->entries[0]);
+
+    if(func_decl->is_public)
+        desc->is_public = TRUE;
+
+    return create_function(ctx, func_decl, desc->entries);
+}
+
 static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
 {
+    function_decl_t *func_decl;
     class_desc_t *class_desc;
+    unsigned i;
+    HRESULT hres;
 
     if(lookup_dim_decls(ctx, class_decl->name) || lookup_funcs_name(ctx, class_decl->name)
             || lookup_class_name(ctx, class_decl->name)) {
@@ -822,6 +839,22 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
     if(!class_desc->name)
         return E_OUTOFMEMORY;
 
+    class_desc->func_cnt = 1; /* always allocate slot for default getter */
+
+    for(func_decl = class_decl->funcs; func_decl; func_decl = func_decl->next)
+        class_desc->func_cnt++;
+
+    class_desc->funcs = compiler_alloc(ctx->code, class_desc->func_cnt*sizeof(*class_desc->funcs));
+    if(!class_desc->funcs)
+        return E_OUTOFMEMORY;
+    memset(class_desc->funcs, 0, class_desc->func_cnt*sizeof(*class_desc->funcs));
+
+    for(func_decl = class_decl->funcs, i=1; func_decl; func_decl = func_decl->next, i++) {
+        hres = create_class_funcprop(ctx, func_decl, class_desc->funcs + i);
+        if(FAILED(hres))
+            return hres;
+    }
+
     class_desc->next = ctx->classes;
     ctx->classes = class_desc;
     return S_OK;
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 014e480..11a5862 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -55,9 +55,24 @@ typedef struct named_item_t {
     struct list entry;
 } named_item_t;
 
+typedef enum {
+    VBDISP_CALLGET,
+    VBDISP_LET,
+    VBDISP_SET,
+    VBDISP_ANY
+} vbdisp_invoke_type_t;
+
+typedef struct {
+    const WCHAR *name;
+    BOOL is_public;
+    function_t *entries[VBDISP_ANY];
+} vbdisp_funcprop_desc_t;
+
 typedef struct _class_desc_t {
     const WCHAR *name;
     script_ctx_t *ctx;
+    unsigned func_cnt;
+    vbdisp_funcprop_desc_t *funcs;
     struct _class_desc_t *next;
 } class_desc_t;
 
@@ -69,13 +84,6 @@ typedef struct {
     const class_desc_t *desc;
 } vbdisp_t;
 
-typedef enum {
-    VBDISP_CALLGET,
-    VBDISP_LET,
-    VBDISP_SET,
-    VBDISP_ANY
-} vbdisp_invoke_type_t;
-
 HRESULT create_vbdisp(const class_desc_t*,vbdisp_t**);
 HRESULT disp_get_id(IDispatch*,BSTR,DISPID*);
 HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,DISPPARAMS*,VARIANT*);

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 15/19] vbscript: Added beginning GetDispID implementation
Message-Id: <4E71EDB9.4000007 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:21:13 +0200

---
  dlls/vbscript/tests/lang.vbs |    4 ++-
  dlls/vbscript/tests/run.c    |   62 
++++++++++++++++++++++++++++++++++++++++-
  dlls/vbscript/vbdisp.c       |   34 +++++++++++++++++++++-
  3 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 2f78403..3f39a4e 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -394,8 +394,10 @@ Class TestClass
     Public Sub publicSub
     End Sub
 
-    Public Sub privateSub
+    Private Sub privateSub
     End Sub
 End Class
 
+Call testDisp(new testClass)
+
 reportSuccess()
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c
index fa6eec1..fb6302a 100644
--- a/dlls/vbscript/tests/run.c
+++ b/dlls/vbscript/tests/run.c
@@ -73,6 +73,7 @@ DEFINE_EXPECT(testobj_propput_i);
 #define DISPID_GLOBAL_VBVAR         1005
 #define DISPID_GLOBAL_TESTOBJ       1006
 #define DISPID_GLOBAL_ISNULLDISP    1007
+#define DISPID_GLOBAL_TESTDISP      1008
 
 #define DISPID_TESTOBJ_PROPGET      2000
 #define DISPID_TESTOBJ_PROPPUT      2001
@@ -140,6 +141,46 @@ static BOOL is_english(void)
         && PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
 }
 
+static void test_disp(IDispatch *disp)
+{
+    DISPID id, public_func_id, public_sub_id;
+    IDispatchEx *dispex;
+    BSTR str;
+    HRESULT hres;
+
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres);
+
+    str = a2bstr("publicFunction");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &public_func_id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(publicFunction) failed: %08x\n", hres);
+    ok(public_func_id != -1, "public_func_id = -1\n");
+
+    str = a2bstr("publicSub");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &public_sub_id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(publicSub) failed: %08x\n", hres);
+    ok(public_sub_id != -1, "public_func_id = -1\n");
+
+    str = a2bstr("privateSub");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &id);
+    SysFreeString(str);
+    ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(privateSub) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
+    ok(id == -1, "id = %d\n", id);
+
+    str = a2bstr("dynprop");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive|fdexNameEnsure, &id);
+    ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(privateProp) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
+    ok(id == -1, "id = %d\n", id);
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameEnsure, &id);
+    ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(privateProp) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
+    ok(id == -1, "id = %d\n", id);
+    SysFreeString(str);
+
+    IDispatchEx_Release(dispex);
+}
+
 #define test_grfdex(a,b) _test_grfdex(__LINE__,a,b)
 static void _test_grfdex(unsigned line, DWORD grfdex, DWORD expect)
 {
@@ -359,7 +400,11 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
         *pid = DISPID_GLOBAL_ISNULLDISP;
         return S_OK;
     }
-
+    if(!strcmp_wa(bstrName, "testDisp")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_TESTDISP;
+        return S_OK;
+    }
 
     if(strict_dispid_check && strcmp_wa(bstrName, "x"))
         ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
@@ -473,7 +518,6 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
 
         ok(V_VT(pdp->rgvarg) == VT_I2, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
         ok(V_I2(pdp->rgvarg) == 3, "V_I2(psp->rgvargs) = %d\n", V_I2(pdp->rgvarg));
-
         return S_OK;
 
     case DISPID_GLOBAL_TESTOBJ:
@@ -512,6 +556,20 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
         V_BOOL(pvarRes) = V_DISPATCH(v) ? VARIANT_FALSE : VARIANT_TRUE;
         return S_OK;
     }
+
+    case DISPID_GLOBAL_TESTDISP:
+        ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
+        ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(!pvarRes, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
+        test_disp(V_DISPATCH(pdp->rgvarg));
+        return S_OK;
     }
 
     ok(0, "unexpected call %d\n", id);
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index f1a323d..77837c6 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -22,6 +22,25 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
 
+static BOOL get_func_id(vbdisp_t *This, const WCHAR *name, BOOL search_private, DISPID *id)
+{
+    unsigned i;
+
+    for(i = 0; i < This->desc->func_cnt; i++) {
+        if(!search_private && !This->desc->funcs[i].is_public)
+            continue;
+        if(!This->desc->funcs[i].name) /* default value may not exist */
+            continue;
+
+        if(!strcmpiW(This->desc->funcs[i].name, name)) {
+            *id = i;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
 static inline vbdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
 {
     return CONTAINING_RECORD(iface, vbdisp_t, IDispatchEx_iface);
@@ -112,8 +131,19 @@ static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
 {
     vbdisp_t *This = impl_from_IDispatchEx(iface);
-    FIXME("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
-    return E_NOTIMPL;
+
+    TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
+
+    if(grfdex & ~(fdexNameEnsure|fdexNameCaseInsensitive)) {
+        FIXME("unsupported flags %x\n", grfdex);
+        return E_NOTIMPL;
+    }
+
+    if(get_func_id(This, bstrName, FALSE, pid))
+        return S_OK;
+
+    *pid = -1;
+    return DISP_E_UNKNOWNNAME;
 }
 
 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,

From: Jacek Caban <jacek at codeweavers.com>
Subject: [PATCH 16/19] vbscript: Added beginning InvokeEx implementation
Message-Id: <4E71EDCD.1050409 at codeweavers.com>
Date: Thu, 15 Sep 2011 14:21:33 +0200

---
  dlls/vbscript/tests/lang.vbs |    5 +++++
  dlls/vbscript/tests/run.c    |   26 ++++++++++++++++++++++++++
  dlls/vbscript/vbdisp.c       |   35 ++++++++++++++++++++++++++++++++++-
  3 files changed, 65 insertions(+), 1 deletions(-)

diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 3f39a4e..ec85614 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -400,4 +400,9 @@ End Class
 
 Call testDisp(new testClass)
 
+Set obj = New TestClass
+
+Call ok(obj.publicFunction = 4, "obj.publicFunction = " & obj.publicFunction)
+Call ok(obj.publicFunction() = 4, "obj.publicFunction() = " & obj.publicFunction())
+
 reportSuccess()
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c
index fb6302a..d98cf38 100644
--- a/dlls/vbscript/tests/run.c
+++ b/dlls/vbscript/tests/run.c
@@ -144,7 +144,11 @@ static BOOL is_english(void)
 static void test_disp(IDispatch *disp)
 {
     DISPID id, public_func_id, public_sub_id;
+    DISPID named_args[5] = {DISPID_PROPERTYPUT};
+    VARIANT v, args[5];
+    DISPPARAMS dp = {args, named_args};
     IDispatchEx *dispex;
+    EXCEPINFO ei = {0};
     BSTR str;
     HRESULT hres;
 
@@ -163,6 +167,28 @@ static void test_disp(IDispatch *disp)
     ok(hres == S_OK, "GetDispID(publicSub) failed: %08x\n", hres);
     ok(public_sub_id != -1, "public_func_id = -1\n");
 
+    dp.cArgs = dp.cNamedArgs = 0;
+    hres = IDispatchEx_InvokeEx(dispex, public_func_id, 0, DISPATCH_PROPERTYGET|DISPATCH_METHOD, &dp, &v, &ei, NULL);
+    ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    ok(V_VT(&v) == VT_I2, "V_VT(v) = %d\n", V_VT(&v));
+    ok(V_I2(&v) == 4, "V_I2(v) = %d\n", V_I2(&v));
+
+    dp.cArgs = dp.cNamedArgs = 0;
+    hres = IDispatchEx_InvokeEx(dispex, public_func_id, 0, DISPATCH_METHOD, &dp, &v, &ei, NULL);
+    ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    ok(V_VT(&v) == VT_I2, "V_VT(v) = %d\n", V_VT(&v));
+    ok(V_I2(&v) == 4, "V_I2(v) = %d\n", V_I2(&v));
+
+    dp.cArgs = dp.cNamedArgs = 0;
+    hres = IDispatchEx_InvokeEx(dispex, public_sub_id, 0, DISPATCH_PROPERTYGET|DISPATCH_METHOD, &dp, &v, &ei, NULL);
+    ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    ok(V_VT(&v) == VT_EMPTY, "V_VT(v) = %d\n", V_VT(&v));
+
+    dp.cArgs = dp.cNamedArgs = 0;
+    hres = IDispatchEx_InvokeEx(dispex, public_sub_id, 0, DISPATCH_METHOD, &dp, &v, &ei, NULL);
+    ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    ok(V_VT(&v) == VT_EMPTY, "V_VT(v) = %d\n", V_VT(&v));
+
     str = a2bstr("privateSub");
     hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &id);
     SysFreeString(str);
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index 77837c6..2b60926 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -22,6 +22,11 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
 
+static inline BOOL is_func_id(vbdisp_t *This, DISPID id)
+{
+    return id < This->desc->func_cnt;
+}
+
 static BOOL get_func_id(vbdisp_t *This, const WCHAR *name, BOOL search_private, DISPID *id)
 {
     unsigned i;
@@ -150,7 +155,35 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
 {
     vbdisp_t *This = impl_from_IDispatchEx(iface);
-    FIXME("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
+
+    TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
+
+    if(pvarRes)
+        V_VT(pvarRes) = VT_EMPTY;
+
+    if(id < 0)
+        return DISP_E_MEMBERNOTFOUND;
+
+    if(is_func_id(This, id)) {
+        function_t *func;
+
+        switch(wFlags) {
+        case DISPATCH_METHOD:
+        case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
+            func = This->desc->funcs[id].entries[VBDISP_CALLGET];
+            if(!func) {
+                FIXME("no invoke/getter\n");
+                return DISP_E_MEMBERNOTFOUND;
+            }
+
+            return exec_script(This->desc->ctx, func, pdp, pvarRes);
+        default:
+            FIXME("flags %x\n", wFlags);
+            return DISP_E_MEMBERNOTFOUND;
+        }
+    }
+
+    FIXME("not implemented for non-function ids\n");
     return DISP_E_MEMBERNOTFOUND;
 }
 



More information about the wine-tests-results mailing list