[VBSCRIPT_WINETEST] Sync with Wine Staging 4.18. CORE-16441
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 1 Dec 2019 18:43:01 +0000 (19:43 +0100)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 1 Dec 2019 18:43:01 +0000 (19:43 +0100)
modules/rostests/winetests/vbscript/api.vbs
modules/rostests/winetests/vbscript/lang.vbs
modules/rostests/winetests/vbscript/run.c
modules/rostests/winetests/vbscript/vbscript.c

index 8ebbfb6..49dd495 100644 (file)
@@ -129,6 +129,16 @@ TestCStr 3, "3"
 if isEnglishLang then TestCStr 3.5, "3.5"
 if isEnglishLang then TestCStr true, "True"
 
+sub testCStrError()
+    on error resume next
+    Error.clear()
+    CStr(null)
+    call ok(Err.number = 94, "Err.number = " & Err.number)
+    if isEnglishLang then call ok(Err.source = "Microsoft VBScript runtime error", "Err.source = " & Err.source)
+    if isEnglishLang then call ok(Err.description = "Invalid use of Null", "Err.description = " & Err.description)
+end sub
+call testCStrError()
+
 Call ok(getVT(Chr(120)) = "VT_BSTR", "getVT(Chr(120)) = " & getVT(Chr(120)))
 Call ok(getVT(Chr(255)) = "VT_BSTR", "getVT(Chr(255)) = " & getVT(Chr(255)))
 Call ok(Chr(120) = "x", "Chr(120) = " & Chr(120))
@@ -144,6 +154,7 @@ sub testChrError
         call Err.clear()
         call Chr(-1)
         call ok(Err.number = 5, "Err.number = " & Err.number)
+        if isEnglishLang then call ok(Err.description = "Invalid procedure call or argument", "Err.description = " & Err.description)
 
         call Err.clear()
         call Chr(256)
@@ -237,6 +248,19 @@ Call ok(UBound(arr2) = 2, "UBound(x) = " & UBound(x))
 Call ok(UBound(arr2, 1) = 2, "UBound(x) = " & UBound(x))
 Call ok(UBound(arr2, 2) = 4, "UBound(x) = " & UBound(x))
 
+sub testUBoundError()
+    on error resume next
+    call Err.clear()
+    call UBound()
+    call ok(Err.number = 450, "Err.number = " & Err.number)
+    call Err.clear()
+    call UBound(arr, 1, 2)
+    call ok(Err.number = 450, "Err.number = " & Err.number)
+    if isEnglishLang then call ok(Err.description = "Wrong number of arguments or invalid property assignment", _
+                                  "Err.description = " & Err.description)
+end sub
+call testUBoundError()
+
 Dim newObject
 Set newObject = New ValClass
 newObject.myval = 1
@@ -494,6 +518,17 @@ TestStrComp "ABC",  Empty,  1,  1
 TestStrComp vbNull, vbNull, 1,  0
 TestStrComp "",     vbNull, 1,  -1
 
+sub testStrCompError()
+    on error resume next
+    call Err.clear()
+    call StrComp()
+    call ok(Err.number = 450, "Err.number = " & Err.number)
+    call Err.clear()
+    call StrComp("a", "a", 0, 1)
+    call ok(Err.number = 450, "Err.number = " & Err.number)
+end sub
+call testStrCompError()
+
 Call ok(Len("abc") = 3, "Len(abc) = " & Len("abc"))
 Call ok(Len("") = 0, "Len() = " & Len(""))
 Call ok(Len(1) = 1, "Len(1) = " & Len(1))
@@ -1066,6 +1101,9 @@ Call ok(VarType(Null) = vbNull, "VarType(Null) = " & VarType(Null))
 Call ok(getVT(VarType(Null)) = "VT_I2", "getVT(VarType(Null)) = " & getVT(VarType(Null)))
 Call ok(VarType(255) = vbInteger, "VarType(255) = " & VarType(255))
 Call ok(getVT(VarType(255)) = "VT_I2", "getVT(VarType(255)) = " & getVT(VarType(255)))
+set x = new EmptyClass
+Call ok(VarType(x) = vbObject, "VarType(x) = " & VarType(x))
+Call ok(getVT(VarType(x)) = "VT_I2", "getVT(VarType(x)) = " & getVT(VarType(x)))
 Call ok(VarType(32768) = vbLong, "VarType(32768) = " & VarType(32768))
 Call ok(getVT(VarType(32768)) = "VT_I2", "getVT(VarType(32768)) = " & getVT(VarType(32768)))
 Call ok(VarType(CSng(0.5)) = vbSingle, "VarType(CSng(0.5)) = " & VarType(CSng(0.5)))
@@ -1080,6 +1118,8 @@ Call ok(VarType(CBool(0.5)) = vbBoolean, "VarType(CBool(0.5)) = " & VarType(CBoo
 Call ok(getVT(VarType(CBool(0.5))) = "VT_I2", "getVT(VarType(CBool(0.5))) = " & getVT(VarType(CBool(0.5))))
 Call ok(VarType(CByte(255)) = vbByte, "VarType(CByte(255)) = " & VarType(CByte(255)))
 Call ok(getVT(VarType(CByte(255))) = "VT_I2", "getVT(VarType(CByte(255))) = " & getVT(VarType(CByte(255))))
+Call ok(VarType(arr) = (vbArray or vbVariant), "VarType(arr) = " & VarType(arr))
+Call ok(getVT(VarType(arr)) = "VT_I2", "getVT(VarType(arr)) = " & getVT(VarType(arr)))
 
 Call ok(Sgn(Empty) = 0, "Sgn(MyEmpty) = " & Sgn(Empty))
 Call ok(getVT(Sgn(Empty)) = "VT_I2", "getVT(Sgn(MyEmpty)) = " & getVT(Sgn(Empty)))
@@ -1407,6 +1447,21 @@ Call ok(getVT(Log(CByte(2))) = "VT_R8", "getVT(Log(CByte(2))) = " & getVT(Log(CB
 Call ok(getVT(Date) = "VT_DATE", "getVT(Date) = " & getVT(Date))
 Call ok(getVT(Time) = "VT_DATE", "getVT(Time) = " & getVT(Time))
 
+Call ok(getVT(Day(now)) = "VT_I2", "getVT(Day(now)) = " & getVT(Day(now)))
+Call ok(Day(2) = 1, "Day(2) = " & Day(2))
+Call ok(getVT(Month(now)) = "VT_I2", "getVT(Month(now)) = " & getVT(Month(now)))
+Call ok(Month(2) = 1, "Month(2) = " & Month(2))
+Call ok(getVT(Year(now)) = "VT_I2", "getVT(Year(now)) = " & getVT(Year(now)))
+Call ok(Year(2) = 1900, "Year(2) = " & Year(2))
+Call ok(getVT(Hour(now)) = "VT_I2", "getVT(Hour(now)) = " & getVT(Hour(now)))
+Call ok(Hour(2) = 0, "Hour(2) = " & Hour(2))
+Call ok(Hour(2.75) = 18, "Hour(2) = " & Hour(2.75))
+Call ok(getVT(Minute(now)) = "VT_I2", "getVT(Minute(now)) = " & getVT(Minute(now)))
+Call ok(Minute(2) = 0, "Minute(2) = " & Minute(2))
+Call ok(Minute(2.02083) = 30, "Minute(2.02083) = " & Minute(2.02083))
+Call ok(getVT(Second(now)) = "VT_I2", "getVT(Second(now)) = " & getVT(Second(now)))
+Call ok(Second(2) = 0, "Second(2) = " & Second(2))
+
 Sub testRGBError(arg1, arg2, arg3, error_num)
     on error resume next
     Dim x
@@ -1431,4 +1486,133 @@ Call testRGBError(&h4d&, -2, &h2f&, 5)
 
 Call ok(getVT(Timer) = "VT_R4", "getVT(Timer) = " & getVT(Timer))
 
+sub testAsc(arg, expected)
+    dim x
+    x = Asc(arg)
+    call ok(x = expected, "x = " & x & " expected " & expected)
+    call ok(getVT(x) = "VT_I2*", "getVT = " & getVT(x))
+end sub
+
+sub testAscError()
+    on error resume next
+    call Err.clear()
+    call Asc(null)
+    Call ok(Err.number = 94, "Err.number = " & Err.number)
+    call Err.clear()
+    call Asc(empty)
+    Call ok(Err.number = 5, "Err.number = " & Err.number)
+    call Err.clear()
+    call Asc()
+    Call ok(Err.number = 450, "Err.number = " & Err.number)
+    call Err.clear()
+    call Asc(Chr(260)) ' some versions of vista allow it
+    Call ok(Err.number = 5 or Err.number = 0, "asc4 Err.number = " & Err.number)
+    call Err.clear()
+    call Asc("")
+    Call ok(Err.number = 5, "Err.number = " & Err.number)
+end sub
+
+call testAsc("T", 84)
+call testAsc("test", 116)
+call testAsc("3", 51)
+call testAsc(3, 51)
+call testAsc("   ", 32)
+call testAsc(Chr(255), 255)
+call testAsc(Chr(0), 0)
+if isEnglishLang then testAsc true, 84
+call testAscError()
+
+sub testErrNumber(n)
+    call ok(err.number = n, "err.number = " & err.number & " expected " & n)
+end sub
+
+sub testErrRaise()
+    on error resume next
+    call ok(err.number = 0, "err.number = " & err.number)
+    err.raise 1
+    call ok(err.number = 1, "err.number = " & err.number)
+    err.raise
+    call ok(err.number = 450, "err.number = " & err.number)
+    call testErrNumber(450)
+    err.raise &h10000&
+    call ok(err.number = 5, "err.number = " & err.number)
+
+    err.clear
+    call ok(getVT(err.source) = "VT_BSTR", "err.source = " & err.source)
+    call ok(getVT(err.description) = "VT_BSTR", "err.description = " & err.description)
+    call ok(getVT(err.helpfile) = "VT_BSTR", "err.helpfile = " & err.helpfile)
+    call ok(getVT(err.helpcontext) = "VT_I4", "err.helpcontext = " & err.helpcontext)
+    call ok(err.source = "", "err.source = " & err.source)
+    call ok(err.description = "", "err.description = " & err.description)
+    call ok(err.helpfile = "", "err.helpfile = " & err.helpfile)
+    call ok(err.helpcontext = 0, "err.helpcontext = " & err.helpcontext)
+
+    err.raise 1, "abc"
+    call ok(err.number = 1, "err.number = " & err.number)
+    call ok(err.source = "abc", "err.source = " & err.source)
+    if isEnglishLang then call ok(err.description = "Unknown runtime error", "err.description = " & err.description)
+    call ok(err.helpfile = "", "err.helpfile = " & err.helpfile)
+
+    err.raise 1, 2, "desc", "hf", 1
+    call ok(err.number = 1, "err.number = " & err.number)
+    call ok(getVT(err.source) = "VT_BSTR", "err.source = " & err.source)
+    call ok(err.source = "2", "err.source = " & err.source)
+    call ok(err.description = "desc", "err.description = " & err.description)
+    call ok(err.helpfile = "hf", "err.helpfile = " & err.helpfile)
+    call ok(getVT(err.helpcontext) = "VT_I4", "err.helpcontext = " & err.helpcontext)
+    call ok(err.helpcontext = 1, "err.helpcontext = " & err.helpcontext)
+
+    err.raise 5
+    call ok(err.number = 5, "err.number = " & err.number)
+    call ok(err.source = "2", "err.source = " & err.source)
+    call ok(err.description = "desc", "err.description = " & err.description)
+    call ok(err.helpfile = "hf", "err.helpfile = " & err.helpfile)
+    call ok(getVT(err.helpcontext) = "VT_I4", "err.helpcontext = " & err.helpcontext)
+    call ok(err.helpcontext = 1, "err.helpcontext = " & err.helpcontext)
+
+    err.clear
+    err.raise &h8007000E&
+    call ok(err.number = 7, "err.number = " & err.number)
+    if isEnglishLang then call ok(err.source = "Microsoft VBScript runtime error", "err.source = " & err.source)
+    if isEnglishLang then call ok(err.description = "Out of memory", "err.description = " & err.description)
+    call ok(err.helpfile = "", "err.helpfile = " & err.helpfile)
+    call ok(err.helpcontext = 0, "err.helpcontext = " & err.helpcontext)
+
+    err.clear
+    err.raise 1, "test"
+    err.raise &h8007000E&
+    call ok(err.number = 7, "err.number = " & err.number)
+    call ok(err.source = "test", "err.source = " & err.source)
+    if isEnglishLang then call ok(err.description = "Unknown runtime error", "err.description = " & err.description)
+    call ok(err.helpfile = "", "err.helpfile = " & err.helpfile)
+    call ok(err.helpcontext = 0, "err.helpcontext = " & err.helpcontext)
+
+    err.raise 1, 2, "desc", "hf", 1
+    err.unknownIdent
+    call ok(err.number = 438, "err.number = " & err.number)
+    if isEnglishLang then call ok(err.source = "Microsoft VBScript runtime error", "err.source = " & err.source)
+    if isEnglishLang then call ok(err.description = "Object doesn't support this property or method", _
+                                  "err.description = " & err.description)
+    call ok(err.helpfile = "", "err.helpfile = " & err.helpfile)
+    call ok(err.helpcontext = 0, "err.helpcontext = " & err.helpcontext)
+
+    e = err
+    call ok(getVT(e) = "VT_I4*", "getVT(e) = " & getVT(e))
+    call ok(e = 438, "e = " & e)
+
+    err.raise 1, 2, "desc", "hf", 1
+    on error goto 0
+    call ok(err.number = 0, "err.number = " & err.number)
+    call ok(err.source = "", "err.source = " & err.source)
+    call ok(err.description = "", "err.description = " & err.description)
+    call ok(err.helpfile = "", "err.helpfile = " & err.helpfile)
+    call ok(err.helpcontext = 0, "err.helpcontext = " & err.helpcontext)
+
+    dim e
+    e = err
+    call ok(getVT(e) = "VT_I4*", "getVT(e) = " & getVT(e))
+    call ok(e = 0, "e = " & e)
+end sub
+call testErrRaise()
+
 Call reportSuccess()
index 2af77bd..6ddb2e7 100644 (file)
@@ -41,6 +41,7 @@ Call ok(10. = 10, "10. <> 10")
 Call ok(&hffFFffFF& = -1, "&hffFFffFF& <> -1")
 Call ok(&hffFFffFF& = -1, "&hffFFffFF& <> -1")
 Call ok(34e5 = 3400000, "34e5 <> 3400000")
+Call ok(34e+5 = 3400000, "34e+5 <> 3400000")
 Call ok(56.789e5 = 5678900, "56.789e5 = 5678900")
 Call ok(56.789e-2 = 0.56789, "56.789e-2 <> 0.56789")
 Call ok(1e-94938484 = 0, "1e-... <> 0")
@@ -1093,6 +1094,14 @@ Call ok(getVT(cs) = "VT_BSTR", "getVT(cs) = " & getVT(cs))
 Call ok(isNull(cnull), "cnull = " & cnull)
 Call ok(getVT(cnull) = "VT_NULL", "getVT(cnull) = " & getVT(cnull))
 
+Call ok(+1 = 1, "+1 != 1")
+Call ok(+true = true, "+1 != 1")
+Call ok(getVT(+true) = "VT_BOOL", "getVT(+true) = " & getVT(+true))
+Call ok(+"true" = "true", """+true"" != true")
+Call ok(getVT(+"true") = "VT_BSTR", "getVT(+""true"") = " & getVT(+"true"))
+Call ok(+obj is obj, "+obj != obj")
+Call ok(+--+-+1 = -1, "+--+-+1 != -1")
+
 if false then Const conststr = "str"
 Call ok(conststr = "str", "conststr = " & conststr)
 Call ok(getVT(conststr) = "VT_BSTR", "getVT(conststr) = " & getVT(conststr))
@@ -1345,4 +1354,129 @@ end class
 set x = new RegExp
 Call ok(x.Global = false, "x.Global = " & x.Global)
 
+sub test_nothing_errors
+    dim x
+    on error resume next
+
+    x = 1
+    err.clear
+    x = nothing
+    call ok(err.number = 91, "err.number = " & err.number)
+    call ok(x = 1, "x = " & x)
+
+    err.clear
+    x = not nothing
+    call ok(err.number = 91, "err.number = " & err.number)
+    call ok(x = 1, "x = " & x)
+
+    err.clear
+    x = "" & nothing
+    call ok(err.number = 91, "err.number = " & err.number)
+    call ok(x = 1, "x = " & x)
+end sub
+call test_nothing_errors()
+
+sub test_identifiers
+    ' test keywords that can also be a declared identifier
+    Dim default
+    default = "xx"
+    Call ok(default = "xx", "default = " & default & " expected ""xx""")
+
+    Dim error
+    error = "xx"
+    Call ok(error = "xx", "error = " & error & " expected ""xx""")
+
+    Dim explicit
+    explicit = "xx"
+    Call ok(explicit = "xx", "explicit = " & explicit & " expected ""xx""")
+
+    Dim step
+    step = "xx"
+    Call ok(step = "xx", "step = " & step & " expected ""xx""")
+end sub
+call test_identifiers()
+
+sub test_dotIdentifiers
+    ' test keywords that can also be an identifier after a dot
+    ' Call ok(testObj.rem = 10, "testObj.rem = " & testObj.rem & " expected 10")
+    Call ok(testObj.true = 10, "testObj.true = " & testObj.true & " expected 10")
+    Call ok(testObj.false = 10, "testObj.false = " & testObj.false & " expected 10")
+    Call ok(testObj.not = 10, "testObj.not = " & testObj.not & " expected 10")
+    Call ok(testObj.and = 10, "testObj.and = " & testObj.and & " expected 10")
+    Call ok(testObj.or = 10, "testObj.or = " & testObj.or & " expected 10")
+    Call ok(testObj.xor = 10, "testObj.xor = " & testObj.xor & " expected 10")
+    Call ok(testObj.eqv = 10, "testObj.eqv = " & testObj.eqv & " expected 10")
+    Call ok(testObj.imp = 10, "testObj.imp = " & testObj.imp & " expected 10")
+    Call ok(testObj.is = 10, "testObj.is = " & testObj.is & " expected 10")
+    Call ok(testObj.mod = 10, "testObj.mod = " & testObj.mod & " expected 10")
+    Call ok(testObj.call = 10, "testObj.call = " & testObj.call & " expected 10")
+    Call ok(testObj.dim = 10, "testObj.dim = " & testObj.dim & " expected 10")
+    Call ok(testObj.sub = 10, "testObj.sub = " & testObj.sub & " expected 10")
+    Call ok(testObj.function = 10, "testObj.function = " & testObj.function & " expected 10")
+    Call ok(testObj.get = 10, "testObj.get = " & testObj.get & " expected 10")
+    Call ok(testObj.let = 10, "testObj.let = " & testObj.let & " expected 10")
+    Call ok(testObj.const = 10, "testObj.const = " & testObj.const & " expected 10")
+    Call ok(testObj.if = 10, "testObj.if = " & testObj.if & " expected 10")
+    Call ok(testObj.else = 10, "testObj.else = " & testObj.else & " expected 10")
+    Call ok(testObj.elseif = 10, "testObj.elseif = " & testObj.elseif & " expected 10")
+    Call ok(testObj.end = 10, "testObj.end = " & testObj.end & " expected 10")
+    Call ok(testObj.then = 10, "testObj.then = " & testObj.then & " expected 10")
+    Call ok(testObj.exit = 10, "testObj.exit = " & testObj.exit & " expected 10")
+    Call ok(testObj.while = 10, "testObj.while = " & testObj.while & " expected 10")
+    Call ok(testObj.wend = 10, "testObj.wend = " & testObj.wend & " expected 10")
+    Call ok(testObj.do = 10, "testObj.do = " & testObj.do & " expected 10")
+    Call ok(testObj.loop = 10, "testObj.loop = " & testObj.loop & " expected 10")
+    Call ok(testObj.until = 10, "testObj.until = " & testObj.until & " expected 10")
+    Call ok(testObj.for = 10, "testObj.for = " & testObj.for & " expected 10")
+    Call ok(testObj.to = 10, "testObj.to = " & testObj.to & " expected 10")
+    Call ok(testObj.each = 10, "testObj.each = " & testObj.each & " expected 10")
+    Call ok(testObj.in = 10, "testObj.in = " & testObj.in & " expected 10")
+    Call ok(testObj.select = 10, "testObj.select = " & testObj.select & " expected 10")
+    Call ok(testObj.case = 10, "testObj.case = " & testObj.case & " expected 10")
+    Call ok(testObj.byref = 10, "testObj.byref = " & testObj.byref & " expected 10")
+    Call ok(testObj.byval = 10, "testObj.byval = " & testObj.byval & " expected 10")
+    Call ok(testObj.option = 10, "testObj.option = " & testObj.option & " expected 10")
+    Call ok(testObj.nothing = 10, "testObj.nothing = " & testObj.nothing & " expected 10")
+    Call ok(testObj.empty = 10, "testObj.empty = " & testObj.empty & " expected 10")
+    Call ok(testObj.null = 10, "testObj.null = " & testObj.null & " expected 10")
+    Call ok(testObj.class = 10, "testObj.class = " & testObj.class & " expected 10")
+    Call ok(testObj.set = 10, "testObj.set = " & testObj.set & " expected 10")
+    Call ok(testObj.new = 10, "testObj.new = " & testObj.new & " expected 10")
+    Call ok(testObj.public = 10, "testObj.public = " & testObj.public & " expected 10")
+    Call ok(testObj.private = 10, "testObj.private = " & testObj.private & " expected 10")
+    Call ok(testObj.next = 10, "testObj.next = " & testObj.next & " expected 10")
+    Call ok(testObj.on = 10, "testObj.on = " & testObj.on & " expected 10")
+    Call ok(testObj.resume = 10, "testObj.resume = " & testObj.resume & " expected 10")
+    Call ok(testObj.goto = 10, "testObj.goto = " & testObj.goto & " expected 10")
+end sub
+call test_dotIdentifiers
+
+' Test End statements not required to be preceeded by a newline or separator
+Sub EndTestSub
+    x = 1 End Sub
+
+Sub EndTestSubWithCall
+    x = 1
+    Call ok(x = 1, "x = " & x)End Sub
+Call EndTestSubWithCall()
+
+Function EndTestFunc(x)
+    Call ok(x > 0, "x = " & x)End Function
+EndTestFunc(1)
+
+Class EndTestClassWithStorageId
+    Public x End Class
+
+Class EndTestClassWithDim
+    Dim x End Class
+
+Class EndTestClassWithFunc
+    Function test(ByVal x)
+        x = 0 End Function End Class
+
+Class EndTestClassWithProperty
+    Public x
+    Public default Property Get defprop
+        defprop = x End Property End Class
+
 reportSuccess()
index 191f5a7..2d34a8c 100644 (file)
@@ -58,6 +58,9 @@ extern const CLSID CLSID_VBScriptRegExp;
 #define SET_EXPECT(func) \
     expect_ ## func = TRUE
 
+#define REF_EXPECT(func) \
+    (&expect_ ## func), (&called_ ## func)
+
 #define CHECK_EXPECT2(func) \
     do { \
         ok(expect_ ##func, "unexpected call " #func "\n"); \
@@ -76,6 +79,12 @@ extern const CLSID CLSID_VBScriptRegExp;
         expect_ ## func = called_ ## func = FALSE; \
     }while(0)
 
+#define CHECK_NOT_CALLED(func) \
+    do { \
+        ok(!called_ ## func, "unexpected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
 #define CLEAR_CALLED(func) \
     expect_ ## func = called_ ## func = FALSE
 
@@ -85,6 +94,7 @@ DEFINE_EXPECT(global_vbvar_d);
 DEFINE_EXPECT(global_vbvar_i);
 DEFINE_EXPECT(global_letobj_i);
 DEFINE_EXPECT(global_setobj_i);
+DEFINE_EXPECT(global_globalcallback_i);
 DEFINE_EXPECT(testobj_propget_d);
 DEFINE_EXPECT(testobj_propget_i);
 DEFINE_EXPECT(testobj_propput_d);
@@ -95,12 +105,15 @@ DEFINE_EXPECT(global_propargput_i);
 DEFINE_EXPECT(global_propargput1_d);
 DEFINE_EXPECT(global_propargput1_i);
 DEFINE_EXPECT(global_testoptionalarg_i);
+DEFINE_EXPECT(global_testerrorobject_i);
 DEFINE_EXPECT(collectionobj_newenum_i);
 DEFINE_EXPECT(Next);
 DEFINE_EXPECT(GetWindow);
 DEFINE_EXPECT(GetUIBehavior);
 DEFINE_EXPECT(EnableModeless);
 DEFINE_EXPECT(OnScriptError);
+DEFINE_EXPECT(OnEnterScript);
+DEFINE_EXPECT(OnLeaveScript);
 
 #define DISPID_GLOBAL_REPORTSUCCESS 1000
 #define DISPID_GLOBAL_TRACE         1001
@@ -124,9 +137,12 @@ DEFINE_EXPECT(OnScriptError);
 #define DISPID_GLOBAL_SETOBJ        1019
 #define DISPID_GLOBAL_TODO_WINE_OK  1020
 #define DISPID_GLOBAL_WEEKSTARTDAY  1021
+#define DISPID_GLOBAL_GLOBALCALLBACK  1022
+#define DISPID_GLOBAL_TESTERROROBJECT 1023
 
 #define DISPID_TESTOBJ_PROPGET      2000
 #define DISPID_TESTOBJ_PROPPUT      2001
+#define DISPID_TESTOBJ_KEYWORD      2002
 
 #define DISPID_COLLOBJ_RESET        3000
 
@@ -143,6 +159,7 @@ static int test_counter;
 static SCRIPTUICHANDLING uic_handling = SCRIPTUICHANDLING_NOUIERROR;
 static IDispatchEx testObj;
 static HRESULT onerror_hres = E_NOTIMPL;
+static BOOL strict_enter_script;
 
 static BSTR a2bstr(const char *str)
 {
@@ -163,6 +180,13 @@ static int strcmp_wa(LPCWSTR strw, const char *stra)
     return lstrcmpA(buf, stra);
 }
 
+static int stricmp_wa(LPCWSTR strw, const char *stra)
+{
+    CHAR buf[512];
+    WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), 0, 0);
+    return lstrcmpiA(buf, stra);
+}
+
 static const char *vt2a(VARIANT *v)
 {
     if(V_VT(v) == (VT_BYREF|VT_VARIANT)) {
@@ -685,7 +709,6 @@ static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pcti
 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
                                               LCID lcid, ITypeInfo **ppTInfo)
 {
-    ok(0, "unexpected call\n");
     return E_NOTIMPL;
 }
 
@@ -756,17 +779,81 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
 
 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);
-        *pid = DISPID_TESTOBJ_PROPPUT;
-        return S_OK;
+    typedef struct {
+          const char * const name;
+          DISPID pid;
+          BOOL *expect;
+          BOOL *called;
+    } dispid_t;
+
+    dispid_t dispids[] = {
+       { "propget", DISPID_TESTOBJ_PROPGET, REF_EXPECT(testobj_propget_d) },
+       { "propput", DISPID_TESTOBJ_PROPPUT, REF_EXPECT(testobj_propput_d) },
+       { "rem", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "true", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "false", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "not", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "and", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "or", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "xor", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "eqv", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "imp", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "is", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "mod", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "call", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "dim", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "sub", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "function", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "get", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "let", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "const", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "if", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "else", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "elseif", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "end", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "then", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "exit", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "while", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "wend", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "do", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "loop", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "until", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "for", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "to", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "each", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "in", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "select", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "case", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "byref", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "byval", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "option", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "nothing", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "empty", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "null", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "class", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "set", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "new", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "public", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "private", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "next", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "on", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "resume", DISPID_TESTOBJ_KEYWORD, NULL },
+       { "goto", DISPID_TESTOBJ_KEYWORD, NULL },
+    };
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(dispids); i++) {
+        if(!stricmp_wa(bstrName, dispids[i].name)) {
+            dispid_t *d = &dispids[i];
+            if(d->expect) {
+               ok(*d->expect, "unexpected call %s\n", d->name);
+               *d->called = TRUE;
+               *d->expect = FALSE;
+            }
+            test_grfdex(grfdex, fdexNameCaseInsensitive);
+            *pid = d->pid;
+            return S_OK;
+        }
     }
 
     ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName));
@@ -831,6 +918,11 @@ static HRESULT WINAPI testObj_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) == 1, "V_I2(psp->rgvargs) = %d\n", V_I2(pdp->rgvarg));
         return S_OK;
+
+    case DISPID_TESTOBJ_KEYWORD:
+        V_VT(pvarRes) = VT_I2;
+        V_I2(pvarRes) = 10;
+        return S_OK;
     }
 
     ok(0, "unexpected call %d\n", id);
@@ -1024,6 +1116,11 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
         *pid = DISPID_GLOBAL_WEEKSTARTDAY;
         return S_OK;
     }
+    if(!strcmp_wa(bstrName, "globalCallback")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_GLOBALCALLBACK;
+        return S_OK;
+    }
     if(!strcmp_wa(bstrName, "testObj")) {
         test_grfdex(grfdex, fdexNameCaseInsensitive);
         *pid = DISPID_GLOBAL_TESTOBJ;
@@ -1102,6 +1199,11 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
         *pid = DISPID_GLOBAL_TESTOPTIONALARG;
         return S_OK;
     }
+    if(!strcmp_wa(bstrName, "testErrorObject")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_TESTERROROBJECT;
+        return S_OK;
+    }
 
     if(strict_dispid_check && strcmp_wa(bstrName, "x"))
         ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
@@ -1480,6 +1582,115 @@ static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid,
         ok(V_ERROR(v) == DISP_E_PARAMNOTFOUND, "V_ERROR(v) = %08x\n", V_ERROR(v));
         return S_OK;
     }
+    case DISPID_GLOBAL_GLOBALCALLBACK: {
+        DISPPARAMS dp = {0};
+        IDispatchEx *dispex;
+        EXCEPINFO ei;
+        VARIANT v;
+        DISPID id;
+        BSTR str;
+        HRESULT hres;
+
+        CHECK_EXPECT(global_globalcallback_i);
+        CHECK_CALLED(OnEnterScript);
+
+        ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(pdp->rgvarg) = %d\n", V_VT(pdp->rgvarg));
+        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");
+
+        hres = IDispatch_QueryInterface(V_DISPATCH(pdp->rgvarg), &IID_IDispatchEx, (void**)&dispex);
+        ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres);
+
+        str = SysAllocString(L"callback");
+        hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &id);
+        ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
+        SysFreeString(str);
+
+        SET_EXPECT(OnEnterScript);
+        SET_EXPECT(OnLeaveScript);
+        memset(&ei, 0, sizeof(ei));
+        hres = IDispatchEx_InvokeEx(dispex, id, 0, DISPATCH_METHOD, &dp, &v, &ei, pspCaller);
+        ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+        CHECK_CALLED(OnEnterScript);
+        CHECK_CALLED(OnLeaveScript);
+        ok(V_VT(&v) == VT_BOOL, "V_VT(v) = %d\n", V_VT(&v));
+        ok(V_BOOL(&v) == VARIANT_TRUE, "V_BOOL(v) = %x\n", V_BOOL(&v));
+
+        IDispatchEx_Release(dispex);
+
+        SET_EXPECT(OnLeaveScript);
+        return S_OK;
+    }
+    case DISPID_GLOBAL_TESTERROROBJECT: {
+        ITypeInfo *typeinfo;
+        IDispatchEx *dispex;
+        DISPPARAMS dp;
+        VARIANT v, r;
+        EXCEPINFO ei;
+        IDispatch *disp;
+        WCHAR *names[1];
+        UINT count, i;
+        DISPID id;
+        HRESULT hres;
+
+        static WCHAR props[][32] = { L"clear", L"description", L"helpcontext", L"helpFILE", L"number", L"raise", L"source" };
+
+        CHECK_EXPECT(global_testerrorobject_i);
+
+        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(pdp->rgvarg) = %d\n", V_VT(pdp->rgvarg));
+        disp = V_DISPATCH(pdp->rgvarg);
+        hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+        ok(hres == E_NOINTERFACE, "Could not get IDispatchEx iface: %08x\n", hres);
+
+        hres = IDispatch_GetTypeInfoCount(disp, &count);
+        ok(hres == S_OK, "GetTypeInfoCount returned: %08x\n", hres);
+        ok(count == 0, "count = %u\n", count);
+
+        hres = IDispatch_GetTypeInfo(disp, 0, 0, &typeinfo);
+        ok(hres == DISP_E_BADINDEX, "GetTypeInfo returned: %08x\n", hres);
+
+        for(i = 0; i < ARRAY_SIZE(props); i++) {
+            names[0] = props[i];
+            hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, names, 1, 0, &id);
+            ok(hres == S_OK, "GetIDsOfNames failed: %08x\n", hres);
+            ok(id == i + 1, "%s id = %u\n", wine_dbgstr_w(props[i]), id);
+        }
+
+        memset(&dp, 0, sizeof(dp));
+        memset(&ei, 0, sizeof(ei));
+        V_VT(&v) = VT_ERROR;
+        hres = IDispatch_Invoke(disp, 5, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v, &ei, NULL);
+        ok(hres == S_OK, "Invoke failed: %08x\n", hres);
+        ok(V_VT(&v) == VT_I4, "V_VT(v) = %d\n", V_VT(&v));
+        ok(V_I4(&v) == 1, "V_I4(v) = %d\n", V_I4(&v));
+        hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v, &ei, NULL);
+        ok(hres == S_OK, "Invoke failed: %08x\n", hres);
+        ok(V_VT(&v) == VT_I4, "V_VT(v) = %d\n", V_VT(&v));
+        ok(V_I4(&v) == 1, "V_I4(v) = %d\n", V_I4(&v));
+
+        dp.rgvarg = &v;
+        V_VT(&v) = VT_I4;
+        V_I4(&v) = 6;
+        V_VT(&r) = VT_EMPTY;
+        hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, 6, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &dp, &r, &ei, NULL);
+        ok(hres == S_OK, "Invoke failed: %08x\n", hres);
+        return S_OK;
+    }
     }
 
     ok(0, "unexpected call %d\n", id);
@@ -1651,9 +1862,11 @@ static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, S
     return E_NOTIMPL;
 }
 
+static IActiveScriptError **store_script_error;
+
 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
 {
-    HRESULT hr = onerror_hres;
+    HRESULT hr = onerror_hres, hres;
 
     if(!expect_OnScriptError) {
         EXCEPINFO info;
@@ -1664,7 +1877,18 @@ static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, I
         if(SUCCEEDED(hres))
             hres = IActiveScriptError_GetExceptionInfo(pscripterror, &info);
         if(SUCCEEDED(hres))
-            trace("Error in line %u: %s\n", line+1, wine_dbgstr_w(info.bstrDescription));
+            trace("Error in line %u: %x %s\n", line+1, info.wCode, wine_dbgstr_w(info.bstrDescription));
+    }else {
+        IDispatchEx *dispex;
+
+        hres = IActiveScriptError_QueryInterface(pscripterror, &IID_IDispatchEx, (void**)&dispex);
+        ok(hres == E_NOINTERFACE, "QI(IDispatchEx) returned: %08x\n", hres);
+    }
+
+    if(store_script_error) {
+        IActiveScriptError_AddRef(pscripterror);
+        *store_script_error = pscripterror;
+        store_script_error = NULL;
     }
 
     CHECK_EXPECT(OnScriptError);
@@ -1675,16 +1899,18 @@ static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, I
 
 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
 {
+    if(strict_enter_script)
+        CHECK_EXPECT(OnEnterScript);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
 {
+    if(strict_enter_script)
+        CHECK_EXPECT(OnLeaveScript);
     return E_NOTIMPL;
 }
 
-#undef ACTSCPSITE_THIS
-
 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
     ActiveScriptSite_QueryInterface,
     ActiveScriptSite_AddRef,
@@ -1713,7 +1939,7 @@ static IActiveScript *create_script(void)
     return script;
 }
 
-static IActiveScript *create_and_init_script(DWORD flags)
+static IActiveScript *create_and_init_script(DWORD flags, BOOL start)
 {
     IActiveScriptParse *parser;
     IActiveScript *engine;
@@ -1738,8 +1964,11 @@ static IActiveScript *create_and_init_script(DWORD flags)
             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|flags);
     ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
 
-    hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED);
-    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
+    if (start)
+    {
+        hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED);
+        ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
+    }
 
     return engine;
 }
@@ -1764,7 +1993,7 @@ static HRESULT parse_script(DWORD flags, BSTR script_str, const WCHAR *delim)
     LONG ref;
     HRESULT hres;
 
-    engine = create_and_init_script(flags);
+    engine = create_and_init_script(flags, TRUE);
     if(!engine)
         return S_OK;
 
@@ -1828,13 +2057,17 @@ static void test_parse_context(void)
     static const WCHAR yW[] = {'y',0};
 
     global_ref = 1;
-    engine = create_and_init_script(0);
+    engine = create_and_init_script(0, TRUE);
     if(!engine)
         return;
 
     hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
     ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
 
+    /* NULL code text succeeds but does nothing */
+    hres = IActiveScriptParse_ParseScriptText(parser, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+
     /* unknown identifier context is not a valid argument */
     str = a2bstr("Call reportSuccess()\n");
     hres = IActiveScriptParse_ParseScriptText(parser, str, yW, NULL, NULL, 0, 0, 0, NULL, NULL);
@@ -1891,7 +2124,7 @@ static void _parse_htmlscript_a(unsigned line, const char *src)
     ok_(__FILE__,line)(hres == S_OK, "parse_script failed: %08x\n", hres);
 }
 
-static IDispatchEx *parse_procedure(IActiveScriptParseProcedure2 *parse_proc, const char *src)
+static IDispatchEx *parse_procedure(IActiveScriptParseProcedure2 *parse_proc, const char *src, DWORD flags)
 {
     IDispatchEx *dispex;
     IDispatch *disp;
@@ -1902,7 +2135,7 @@ static IDispatchEx *parse_procedure(IActiveScriptParseProcedure2 *parse_proc, co
 
     str = a2bstr(src);
     hres = IActiveScriptParseProcedure2_ParseProcedureText(parse_proc, str, NULL, emptyW, NULL, NULL, delimiterW, 0, 0,
-            SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
+            SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS|flags, &disp);
     SysFreeString(str);
     ok(hres == S_OK, "ParseProcedureText failed: %08x\n", hres);
     ok(disp != NULL, "disp = NULL\n");
@@ -1921,26 +2154,220 @@ static void test_procedures(void)
     DISPPARAMS dp = {NULL};
     IActiveScript *script;
     IDispatchEx *proc;
+    IDispatch *disp;
     EXCEPINFO ei = {0};
     VARIANT v;
     HRESULT hres;
 
-    script = create_and_init_script(0);
+    strict_enter_script = TRUE;
+    script = create_and_init_script(0, TRUE);
 
     hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParseProcedure2, (void**)&parse_proc);
     ok(hres == S_OK, "Could not get IActiveScriptParseProcedure2 iface: %08x\n", hres);
 
-    proc = parse_procedure(parse_proc, "dim x\nif true then x=false");
+    hres = IActiveScriptParseProcedure2_ParseProcedureText(parse_proc, NULL, NULL, emptyW, NULL, NULL, NULL, 0, 0, 0, &disp);
+    ok(hres == S_OK, "ParseProcedureText failed: %08x\n", hres);
+    IDispatch_Release(disp);
+
+    proc = parse_procedure(parse_proc, "dim x\nif true then x=false", 0);
 
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
     V_VT(&v) = VT_EMPTY;
     hres = IDispatchEx_InvokeEx(proc, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, &v, &ei, &caller_sp);
     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+    VariantClear(&v);
+    IDispatchEx_Release(proc);
+
+    proc = parse_procedure(parse_proc, "\"foobar\"", SCRIPTPROC_ISEXPRESSION);
 
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    hres = IDispatchEx_InvokeEx(proc, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, &v, &ei, &caller_sp);
+    ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+    ok(V_VT(&v) == VT_BSTR, "Expected VT_BSTR, got %s\n", vt2a(&v));
+    ok(!strcmp_wa(V_BSTR(&v), "foobar"), "Wrong string, got %s\n", wine_dbgstr_w(V_BSTR(&v)));
+    VariantClear(&v);
     IDispatchEx_Release(proc);
 
     IActiveScriptParseProcedure2_Release(parse_proc);
 
     close_script(script);
+    strict_enter_script = FALSE;
+}
+
+static void free_ei(EXCEPINFO *ei)
+{
+    SysFreeString(ei->bstrSource);
+    SysFreeString(ei->bstrDescription);
+    SysFreeString(ei->bstrHelpFile);
+}
+
+static void test_callbacks(void)
+{
+    IActiveScriptError *error1, *error2;
+    IActiveScriptParse *parser;
+    DISPPARAMS dp = {NULL};
+    IActiveScript *script;
+    IDispatchEx *dispex;
+    IDispatch *disp;
+    DISPID id;
+    EXCEPINFO ei = {0};
+    BSTR str;
+    VARIANT v;
+    HRESULT hres;
+
+    strict_enter_script = TRUE;
+    script = create_and_init_script(SCRIPTITEM_GLOBALMEMBERS, TRUE);
+
+    hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParseProcedure2 iface: %08x\n", hres);
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    hres = IActiveScriptParse_ParseScriptText(parser,
+                                              L"class CallbackClass\n"
+                                              L"    public function callback()\n"
+                                              L"        call ok(err.number = 2, \"err.number = \" & err.number)\n"
+                                              L"        callback = true\n"
+                                              L"    end function\n"
+                                              L"end class\n"
+                                              L"function callGlobalCallback()\n"
+                                              L"    on error resume next\n"
+                                              L"    err.raise 2\n"
+                                              L"    call test.globalCallback(new CallbackClass)\n"
+                                              L"    call ok(err.number = 2, \"err.number = \" & err.numner)\n"
+                                              L"end function\n",
+                                              NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+
+    hres = IActiveScript_GetScriptDispatch(script, NULL, &disp);
+    ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres);
+
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres);
+    IDispatch_Release(disp);
+
+    str = SysAllocString(L"callGlobalCallback");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &id);
+    ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
+    SysFreeString(str);
+
+    SET_EXPECT(OnEnterScript);
+    /* OnLeaveScript will be set in global callback */
+    SET_EXPECT(global_globalcallback_i);
+    hres = IDispatchEx_InvokeEx(dispex, id, 0, DISPATCH_METHOD, &dp, &v, &ei, &caller_sp);
+    ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    /* OnEnterScript was checked in global callback */
+    CHECK_CALLED(OnLeaveScript);
+    CHECK_CALLED(global_globalcallback_i);
+
+    store_script_error = &error1;
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    SET_EXPECT(OnScriptError);
+    hres = IActiveScriptParse_ParseScriptText(parser, L"err.raise 2\n",
+                                              NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == MAKE_VBSERROR(2), "ParseScriptText failed: %08x\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+    CHECK_CALLED(OnScriptError);
+
+    store_script_error = &error2;
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    SET_EXPECT(OnScriptError);
+    hres = IActiveScriptParse_ParseScriptText(parser,
+                                              L"call ok(err.number = 0, \"err.number = \" & err.number)\n"
+                                              L"err.raise &h86664004&, \"src\", \"desc\", \"help\", 1\n",
+                                              NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == SCRIPT_E_RECORDED, "ParseScriptText failed: %08x\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+    CHECK_CALLED(OnScriptError);
+
+    memset(&ei, 0xcc, sizeof(ei));
+    hres = IActiveScriptError_GetExceptionInfo(error1, &ei);
+    ok(hres == S_OK, "GetExceptionInfo returned %08x\n", hres);
+    ok(!ei.wCode, "wCode = %x\n", ei.wCode);
+    ok(!ei.wReserved, "wReserved = %x\n", ei.wReserved);
+    if(is_english) {
+        ok(!wcscmp(ei.bstrSource, L"Microsoft VBScript runtime error"),
+           "bstrSource = %s\n", wine_dbgstr_w(ei.bstrSource));
+        ok(!wcscmp(ei.bstrDescription, L"Object doesn't support this property or method"),
+           "bstrDescription = %s\n", wine_dbgstr_w(ei.bstrDescription));
+    }
+    ok(!ei.bstrHelpFile, "bstrHelpFile = %s\n", wine_dbgstr_w(ei.bstrHelpFile));
+    ok(!ei.dwHelpContext, "dwHelpContext = %x\n", ei.dwHelpContext);
+    ok(!ei.pvReserved, "pvReserved = %p\n", ei.pvReserved);
+    ok(!ei.pfnDeferredFillIn, "pfnDeferredFillIn = %p\n", ei.pfnDeferredFillIn);
+    ok(ei.scode == MAKE_VBSERROR(2), "scode = %x\n", ei.scode);
+    free_ei(&ei);
+
+    IActiveScriptError_Release(error1);
+
+    memset(&ei, 0xcc, sizeof(ei));
+    hres = IActiveScriptError_GetExceptionInfo(error2, &ei);
+    ok(hres == S_OK, "GetExceptionInfo returned %08x\n", hres);
+    ok(!ei.wCode, "wCode = %x\n", ei.wCode);
+    ok(!ei.wReserved, "wReserved = %x\n", ei.wReserved);
+    ok(!wcscmp(ei.bstrSource, L"src"), "bstrSource = %s\n", wine_dbgstr_w(ei.bstrSource));
+    ok(!wcscmp(ei.bstrDescription, L"desc"), "bstrDescription = %s\n", wine_dbgstr_w(ei.bstrDescription));
+    ok(!wcscmp(ei.bstrHelpFile, L"help"), "bstrHelpFile = %s\n", wine_dbgstr_w(ei.bstrHelpFile));
+    ok(ei.dwHelpContext == 1, "dwHelpContext = %x\n", ei.dwHelpContext);
+    ok(!ei.pvReserved, "pvReserved = %p\n", ei.pvReserved);
+    ok(!ei.pfnDeferredFillIn, "pfnDeferredFillIn = %p\n", ei.pfnDeferredFillIn);
+    ok(ei.scode == SCRIPT_E_RECORDED, "scode = %x\n", ei.scode);
+    free_ei(&ei);
+
+    IActiveScriptError_Release(error2);
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    SET_EXPECT(OnScriptError);
+    hres = IActiveScriptParse_ParseScriptText(parser, L"err.raise &hffff&\n",
+                                              NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == MAKE_VBSERROR(0xffff), "ParseScriptText failed: %08x\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+    CHECK_CALLED(OnScriptError);
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    SET_EXPECT(OnScriptError);
+    hres = IActiveScriptParse_ParseScriptText(parser, L"err.raise &h80102030&\n",
+                                              NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == 0x80102030, "ParseScriptText failed: %08x\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+    CHECK_CALLED(OnScriptError);
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(global_testerrorobject_i);
+    SET_EXPECT(OnLeaveScript);
+    hres = IActiveScriptParse_ParseScriptText(parser,
+                                              L"on error resume next\n"
+                                              L"err.raise 1\n"
+                                              L"testErrorObject err\n",
+                                              NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(global_testerrorobject_i);
+    CHECK_CALLED(OnLeaveScript);
+
+    IDispatchEx_Release(dispex);
+
+    IActiveScriptParse_Release(parser);
+    close_script(script);
+    strict_enter_script = FALSE;
 }
 
 static void test_gc(void)
@@ -1998,6 +2425,62 @@ static void test_gc(void)
     IActiveScriptParse_Release(parser);
 }
 
+static void test_parse_errors(void)
+{
+    static const char *invalid_scripts[] =
+    {
+        /* If...End If */
+        "If 0 > 1 Then\n"
+        "    x = 0 End If\n",
+
+        /* While...End While */
+        "While False\n"
+        "    x = 0 End While\n",
+
+        /* While...Wend */
+        "While False\n"
+        "    x = 0 Wend\n",
+
+        /* Do While...Loop */
+        "Do While False\n"
+        "    x = 0 Loop\n",
+
+        /* Do Until...Loop */
+        "Do Until True\n"
+        "    x = 0 Loop\n",
+
+        /* Do...Loop While */
+        "Do\n"
+        "    x = 0 Loop While False\n",
+
+        /* Do...Loop Until */
+        "Do\n"
+        "    x = 0 Loop Until True\n",
+
+        /* Select...End Select */
+        "x = False\n"
+        "Select Case 42\n"
+        "    Case 0\n"
+        "        Call ok(False, \"unexpected case\")\n"
+        "    Case 42\n"
+        "        x = True End Select\n"
+        "Call ok(x, \"wrong case\")\n",
+
+        /* Class...End Class  (empty) */
+        "Class C End Class"
+    };
+    HRESULT hres;
+    UINT i;
+
+    for (i = 0; i < ARRAY_SIZE(invalid_scripts); i++)
+    {
+        SET_EXPECT(OnScriptError);
+        hres = parse_script_ar(invalid_scripts[i]);
+        ok(FAILED(hres), "[%u] script did not fail\n", i);
+        CHECK_CALLED(OnScriptError);
+    }
+}
+
 static void test_msgbox(void)
 {
     HRESULT hres;
@@ -2035,7 +2518,7 @@ static void test_msgbox(void)
     CHECK_CALLED(GetUIBehavior);
     CHECK_CALLED(GetWindow);
     CHECK_CALLED(EnableModeless);
-    todo_wine CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnScriptError);
 
     uic_handling = SCRIPTUICHANDLING_NOUIERROR;
 
@@ -2044,7 +2527,7 @@ static void test_msgbox(void)
     hres = parse_script_ar("MsgBox \"testing...\"");
     ok(FAILED(hres), "script not failed\n");
     CHECK_CALLED(GetUIBehavior);
-    todo_wine CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnScriptError);
 }
 
 static HRESULT test_global_vars_ref(BOOL use_close)
@@ -2104,6 +2587,141 @@ static HRESULT test_global_vars_ref(BOOL use_close)
     return hres;
 }
 
+static void test_isexpression(void)
+{
+    IActiveScriptParse *parser;
+    IActiveScript *engine;
+    SCRIPTSTATE ss;
+    HRESULT hres;
+    VARIANT var;
+    BSTR str;
+
+    if (!(engine = create_and_init_script(0, FALSE)))
+        return;
+
+    hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
+    if (FAILED(hres))
+    {
+        close_script(engine);
+        return;
+    }
+
+    /* Expression when script is not started is still executed */
+    hres = IActiveScript_GetScriptState(engine, &ss);
+    ok(hres == S_OK, "GetScriptState failed: %08x\n", hres);
+    ok(ss == SCRIPTSTATE_INITIALIZED, "Wrong script state %u\n", ss);
+
+    str = a2bstr("13");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    ok(V_VT(&var) == VT_I2, "Expected VT_I2, got %s\n", vt2a(&var));
+    ok(V_I2(&var) == 13, "Expected 13, got %d\n", V_I2(&var));
+    VariantClear(&var);
+    SysFreeString(str);
+
+    hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
+
+    /* Empty expressions */
+    V_VT(&var) = VT_I2;
+    str = a2bstr("");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    ok(V_VT(&var) == VT_EMPTY, "Expected VT_EMPTY, got %s\n", vt2a(&var));
+    VariantClear(&var);
+    SysFreeString(str);
+
+    /* Two expressions fail */
+    str = a2bstr("1\n3");
+    SET_EXPECT(OnScriptError);
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(FAILED(hres), "ParseScriptText did not fail: %08x\n", hres);
+    CHECK_CALLED(OnScriptError);
+    VariantClear(&var);
+    SysFreeString(str);
+
+    /* Simple numerical expression */
+    str = a2bstr("(1 + 7) * 2 - 3");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    ok(V_VT(&var) == VT_I2, "Expected VT_I2, got %s\n", vt2a(&var));
+    ok(V_I2(&var) == 13, "Expected 13, got %d\n", V_I2(&var));
+    VariantClear(&var);
+    SysFreeString(str);
+
+    /* An expression can also refer to a variable, function, class, etc previously set */
+    V_VT(&var) = VT_I2;
+    str = a2bstr("If True Then foo = 42 Else foo = 0\n");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, &var, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    ok(V_VT(&var) == VT_EMPTY, "Expected VT_EMPTY, got %s\n", vt2a(&var));
+    VariantClear(&var);
+    SysFreeString(str);
+
+    str = a2bstr("foo\n\n");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    ok(V_VT(&var) == VT_I2, "Expected VT_I2, got %s\n", vt2a(&var));
+    ok(V_I2(&var) == 42, "Expected 42, got %d\n", V_I2(&var));
+    VariantClear(&var);
+    SysFreeString(str);
+
+    str = a2bstr("foo : ");
+    SET_EXPECT(OnScriptError);
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(FAILED(hres), "ParseScriptText did not fail: %08x\n", hres);
+    CHECK_CALLED(OnScriptError);
+    VariantClear(&var);
+    SysFreeString(str);
+
+    str = a2bstr("\"foo is \" & CStr(foo)  \n  \n\n ");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    ok(V_VT(&var) == VT_BSTR, "Expected VT_BSTR, got %s\n", vt2a(&var));
+    ok(!strcmp_wa(V_BSTR(&var), "foo is 42"), "Wrong string, got %s\n", wine_dbgstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+    SysFreeString(str);
+
+    str = a2bstr("Function test(x)\n"
+                 "    test = x + 0.5\n"
+                 "End Function\n");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    SysFreeString(str);
+
+    str = a2bstr("test(4) * 3\n");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    ok(V_VT(&var) == VT_R8, "Expected VT_R8, got %s\n", vt2a(&var));
+    ok(V_R8(&var) == 13.5, "Expected %lf, got %lf\n", 13.5, V_R8(&var));
+    VariantClear(&var);
+    SysFreeString(str);
+
+    str = a2bstr("Class C\n"
+                 "    Public x\n"
+                 "End Class\n"
+                 "Set obj = New C\n"
+                 "obj.x = True\n");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    SysFreeString(str);
+
+    str = a2bstr("obj.x");
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &var, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    ok(V_VT(&var) == VT_BOOL, "Expected VT_BOOL, got %s\n", vt2a(&var));
+    ok(V_BOOL(&var) == VARIANT_TRUE, "Expected %x, got %x\n", VARIANT_TRUE, V_BOOL(&var));
+    VariantClear(&var);
+    SysFreeString(str);
+
+    IActiveScriptParse_Release(parser);
+    close_script(engine);
+}
+
 static BSTR get_script_from_file(const char *filename)
 {
     DWORD size, len;
@@ -2186,6 +2804,7 @@ static void run_from_res(const char *name)
 
     ok(hres == S_OK, "parse_script failed: %08x\n", hres);
     SysFreeString(str);
+    test_name = "";
 }
 
 static void run_tests(void)
@@ -2255,6 +2874,13 @@ static void run_tests(void)
     parse_script_a("Option Explicit\nset test.setobj = testObj");
     CHECK_CALLED(global_setobj_i);
 
+    SET_EXPECT(OnScriptError);
+    hres = parse_script_ar("dim x\nx = testObj.rem");
+    todo_wine
+    ok(hres == S_OK, "use of 'rem' as dot identifier failed: %x08\n", hres);
+    todo_wine
+    CHECK_NOT_CALLED(OnScriptError);
+
     SET_EXPECT(testobj_propget_d);
     SET_EXPECT(testobj_propget_i);
     parse_script_a("dim x\nx = testObj.propget");
@@ -2299,7 +2925,7 @@ static void run_tests(void)
     SET_EXPECT(OnScriptError);
     hres = parse_script_ar("<!--");
     ok(FAILED(hres), "script didn't fail\n");
-    todo_wine CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnScriptError);
 
     SET_EXPECT(global_success_d);
     SET_EXPECT(global_success_i);
@@ -2325,36 +2951,36 @@ static void run_tests(void)
     SET_EXPECT(OnScriptError);
     hres = parse_script_ar("throwInt(&h80080008&)");
     ok(hres == 0x80080008, "hres = %08x\n", hres);
-    todo_wine CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnScriptError);
 
     /* DISP_E_BADINDEX */
     SET_EXPECT(OnScriptError);
     hres = parse_script_ar("throwInt(&h8002000b&)");
     ok(hres == MAKE_VBSERROR(9), "hres = %08x\n", hres);
-    todo_wine CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnScriptError);
 
     SET_EXPECT(OnScriptError);
     hres = parse_script_ar("throwInt(&h800a0009&)");
     ok(hres == MAKE_VBSERROR(9), "hres = %08x\n", hres);
-    todo_wine CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnScriptError);
 
     onerror_hres = S_OK;
     SET_EXPECT(OnScriptError);
     hres = parse_script_ar("throwInt(&h800a0009&)");
-    todo_wine ok(hres == SCRIPT_E_REPORTED, "hres = %08x\n", hres);
-    todo_wine CHECK_CALLED(OnScriptError);
+    ok(hres == SCRIPT_E_REPORTED, "hres = %08x\n", hres);
+    CHECK_CALLED(OnScriptError);
 
     /* E_NOTIMPL */
     SET_EXPECT(OnScriptError);
     hres = parse_script_ar("throwInt(&h80004001&)");
     ok(hres == MAKE_VBSERROR(445), "hres = %08x\n", hres);
-    todo_wine CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnScriptError);
 
     onerror_hres = S_OK;
     SET_EXPECT(OnScriptError);
     hres = parse_script_ar("throwInt(&h80004001&)");
-    todo_wine ok(hres == SCRIPT_E_REPORTED, "hres = %08x\n", hres);
-    todo_wine CHECK_CALLED(OnScriptError);
+    ok(hres == SCRIPT_E_REPORTED, "hres = %08x\n", hres);
+    CHECK_CALLED(OnScriptError);
 
     SET_EXPECT(global_testoptionalarg_i);
     parse_script_a("call testOptionalArg(1,,2)");
@@ -2392,11 +3018,14 @@ static void run_tests(void)
     SET_EXPECT(OnScriptError);
     hres = parse_script_ar("x = y(\"a\")");
     ok(FAILED(hres), "script didn't fail\n");
-    todo_wine CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnScriptError);
 
     SET_EXPECT(global_success_d);
     SET_EXPECT(global_success_i);
     parse_script_a("' comment\r"
+                   "x = _\r3\r"
+                   "x = _\n3\r"
+                   "x = _\r\n3\r"
                    "Sub testsub(arg)\r"
                    "If arg = 1 Then\r\r"
                    "Call reportSuccess()\n\n"
@@ -2414,7 +3043,10 @@ static void run_tests(void)
     test_procedures();
     test_gc();
     test_msgbox();
+    test_isexpression();
+    test_parse_errors();
     test_parse_context();
+    test_callbacks();
 }
 
 static BOOL check_vbscript(void)
index 9e86a5f..08edfc1 100644 (file)
@@ -84,6 +84,9 @@ DEFINE_EXPECT(OnStateChange_CLOSED);
 DEFINE_EXPECT(OnStateChange_INITIALIZED);
 DEFINE_EXPECT(OnEnterScript);
 DEFINE_EXPECT(OnLeaveScript);
+DEFINE_EXPECT(GetItemInfo_global);
+DEFINE_EXPECT(GetItemInfo_visible);
+DEFINE_EXPECT(testCall);
 
 DEFINE_GUID(CLSID_VBScript, 0xb54f3741, 0x5b07, 0x11cf, 0xa4,0xb0, 0x00,0xaa,0x00,0x4a,0x55,0xe8);
 DEFINE_GUID(CLSID_VBScriptRegExp, 0x3f4daca4, 0x160d, 0x11d2, 0xa8,0xe9, 0x00,0x10,0x4b,0x36,0x5c,0x9f);
@@ -111,6 +114,95 @@ static void _test_state(unsigned line, IActiveScript *script, SCRIPTSTATE exstat
     ok_(__FILE__,line) (state == exstate, "state=%d, expected %d\n", state, exstate);
 }
 
+static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IDispatch, riid)) {
+        *ppv = iface;
+        IDispatch_AddRef(iface);
+        return S_OK;
+    }
+
+    *ppv = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG global_named_item_ref, visible_named_item_ref;
+
+static ULONG WINAPI global_AddRef(IDispatch *iface)
+{
+    return ++global_named_item_ref;
+}
+
+static ULONG WINAPI global_Release(IDispatch *iface)
+{
+    return --global_named_item_ref;
+}
+
+static ULONG WINAPI visible_AddRef(IDispatch *iface)
+{
+    return ++visible_named_item_ref;
+}
+
+static ULONG WINAPI visible_Release(IDispatch *iface)
+{
+    return --visible_named_item_ref;
+}
+
+static HRESULT WINAPI Dispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Dispatch_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+{
+    return DISP_E_BADINDEX;
+}
+
+static HRESULT WINAPI Dispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *names, UINT name_cnt,
+                                            LCID lcid, DISPID *ids)
+{
+    ok(name_cnt == 1, "name_cnt = %u\n", name_cnt);
+    ok(!wcscmp(names[0], L"testCall"), "names[0] = %s\n", wine_dbgstr_w(names[0]));
+    *ids = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID id, REFIID riid, LCID lcid, WORD flags,
+                                      DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, UINT *err)
+{
+    CHECK_EXPECT(testCall);
+    ok(id == 1, "id = %u\n", id);
+    ok(flags == DISPATCH_METHOD, "flags = %x\n", flags);
+    ok(!dp->cArgs, "cArgs = %u\n", dp->cArgs);
+    ok(!res, "res = %p\n", res);
+    return S_OK;
+}
+
+static const IDispatchVtbl global_named_item_vtbl = {
+    Dispatch_QueryInterface,
+    global_AddRef,
+    global_Release,
+    Dispatch_GetTypeInfoCount,
+    Dispatch_GetTypeInfo,
+    Dispatch_GetIDsOfNames,
+    Dispatch_Invoke
+};
+
+static IDispatch global_named_item = { &global_named_item_vtbl };
+
+static const IDispatchVtbl visible_named_item_vtbl = {
+    Dispatch_QueryInterface,
+    visible_AddRef,
+    visible_Release,
+    Dispatch_GetTypeInfoCount,
+    Dispatch_GetTypeInfo,
+    Dispatch_GetIDsOfNames,
+    Dispatch_Invoke
+};
+
+static IDispatch visible_named_item = { &visible_named_item_vtbl };
+
 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
 {
     *ppv = NULL;
@@ -142,10 +234,23 @@ static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *p
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
-        DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
+static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR name,
+        DWORD return_mask, IUnknown **item_unk, ITypeInfo **item_ti)
 {
-    ok(0, "unexpected call\n");
+    ok(return_mask == SCRIPTINFO_IUNKNOWN, "return_mask = %x\n", return_mask);
+    if(!wcscmp(name, L"globalItem")) {
+        CHECK_EXPECT(GetItemInfo_global);
+        IDispatch_AddRef(&global_named_item);
+        *item_unk = (IUnknown*)&global_named_item;
+        return S_OK;
+    }
+    if(!wcscmp(name, L"visibleItem")) {
+        CHECK_EXPECT(GetItemInfo_visible);
+        IDispatch_AddRef(&visible_named_item);
+        *item_unk = (IUnknown*)&visible_named_item;
+        return S_OK;
+    }
+    ok(0, "unexpected call %s\n", wine_dbgstr_w(name));
     return E_NOTIMPL;
 }
 
@@ -392,8 +497,8 @@ static IActiveScript *create_vbscript(void)
 
 static void test_scriptdisp(void)
 {
+    IDispatchEx *script_disp, *script_disp2;
     IActiveScriptParse *parser;
-    IDispatchEx *script_disp;
     IActiveScript *vbscript;
     DISPID id, id2;
     DISPPARAMS dp;
@@ -415,6 +520,8 @@ static void test_scriptdisp(void)
     ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
     CHECK_CALLED(GetLCID);
 
+    script_disp2 = get_script_dispatch(vbscript);
+
     test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
 
     SET_EXPECT(OnStateChange_INITIALIZED);
@@ -432,6 +539,8 @@ static void test_scriptdisp(void)
     test_state(vbscript, SCRIPTSTATE_CONNECTED);
 
     script_disp = get_script_dispatch(vbscript);
+    ok(script_disp == script_disp2, "script_disp != script_disp2\n");
+    IDispatchEx_Release(script_disp2);
 
     id = 100;
     get_disp_id(script_disp, "LCase", DISP_E_UNKNOWNNAME, &id);
@@ -529,6 +638,7 @@ static void test_vbscript(void)
 
     test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
     test_safety(vbscript);
+    test_no_script_dispatch(vbscript);
 
     SET_EXPECT(GetLCID);
     hres = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite);
@@ -600,6 +710,8 @@ static void test_vbscript_uninitializing(void)
     hres = IActiveScriptParse_InitNew(parse);
     ok(hres == S_OK, "InitNew failed: %08x\n", hres);
 
+    test_no_script_dispatch(script);
+
     SET_EXPECT(GetLCID);
     SET_EXPECT(OnStateChange_INITIALIZED);
     hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
@@ -685,6 +797,9 @@ static void test_vbscript_uninitializing(void)
 
     test_state(script, SCRIPTSTATE_CLOSED);
 
+    hres = IActiveScriptParse_InitNew(parse);
+    ok(hres == E_UNEXPECTED, "InitNew failed: %08x\n", hres);
+
     IActiveScriptParse_Release(parse);
 
     ref = IActiveScript_Release(script);
@@ -794,6 +909,88 @@ static void test_vbscript_initializing(void)
     ok(!ref, "ref = %d\n", ref);
 }
 
+static void test_named_items(void)
+{
+    IActiveScriptParse *parse;
+    IActiveScript *script;
+    ULONG ref;
+    HRESULT hres;
+
+    script = create_vbscript();
+
+    hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parse);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
+
+    test_state(script, SCRIPTSTATE_UNINITIALIZED);
+
+    hres = IActiveScript_AddNamedItem(script, L"visibleItem", SCRIPTITEM_ISVISIBLE);
+    ok(hres == E_UNEXPECTED, "AddNamedItem returned: %08x\n", hres);
+    hres = IActiveScript_AddNamedItem(script, L"globalItem", SCRIPTITEM_GLOBALMEMBERS);
+    ok(hres == E_UNEXPECTED, "AddNamedItem returned: %08x\n", hres);
+
+    SET_EXPECT(GetLCID);
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+    CHECK_CALLED(GetLCID);
+
+    SET_EXPECT(GetItemInfo_global);
+    hres = IActiveScript_AddNamedItem(script, L"globalItem", SCRIPTITEM_GLOBALMEMBERS);
+    ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
+    CHECK_CALLED(GetItemInfo_global);
+
+    hres = IActiveScript_AddNamedItem(script, L"visibleItem", SCRIPTITEM_ISVISIBLE);
+    ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
+
+    ok(global_named_item_ref > 0, "global_named_item_ref = %u\n", global_named_item_ref);
+    ok(visible_named_item_ref == 0, "visible_named_item_ref = %u\n", visible_named_item_ref);
+
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScriptParse_InitNew(parse);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    SET_EXPECT(OnStateChange_CONNECTED);
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_CONNECTED);
+
+    SET_EXPECT(testCall);
+    parse_script(parse, "testCall\n");
+    CHECK_CALLED(testCall);
+
+    SET_EXPECT(GetItemInfo_visible);
+    SET_EXPECT(testCall);
+    parse_script(parse, "visibleItem.testCall\n");
+    CHECK_CALLED(GetItemInfo_visible);
+    CHECK_CALLED(testCall);
+
+    ok(global_named_item_ref > 0, "global_named_item_ref = %u\n", global_named_item_ref);
+    ok(visible_named_item_ref == 1, "visible_named_item_ref = %u\n", visible_named_item_ref);
+
+    SET_EXPECT(testCall);
+    parse_script(parse, "visibleItem.testCall\n");
+    CHECK_CALLED(testCall);
+
+    SET_EXPECT(OnStateChange_DISCONNECTED);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    SET_EXPECT(OnStateChange_CLOSED);
+    hres = IActiveScript_Close(script);
+    ok(hres == S_OK, "Close failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_DISCONNECTED);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+    CHECK_CALLED(OnStateChange_CLOSED);
+
+    ok(global_named_item_ref == 0, "global_named_item_ref = %u\n", global_named_item_ref);
+    ok(visible_named_item_ref == 0, "visible_named_item_ref = %u\n", visible_named_item_ref);
+
+    test_state(script, SCRIPTSTATE_CLOSED);
+
+    IActiveScriptParse_Release(parse);
+
+    ref = IActiveScript_Release(script);
+    ok(!ref, "ref = %d\n", ref);
+}
+
 static void test_RegExp(void)
 {
     IRegExp2 *regexp;
@@ -957,6 +1154,7 @@ START_TEST(vbscript)
         test_vbscript_release();
         test_vbscript_simplecreate();
         test_vbscript_initializing();
+        test_named_items();
         test_scriptdisp();
         test_RegExp();
     }else {