[VBSCRIPT_WINETEST]
authorAmine Khaldi <amine.khaldi@reactos.org>
Wed, 15 May 2013 17:33:58 +0000 (17:33 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Wed, 15 May 2013 17:33:58 +0000 (17:33 +0000)
* Import from Wine 1.5.26.

svn path=/trunk/; revision=59018

12 files changed:
rostests/winetests/CMakeLists.txt
rostests/winetests/vbscript/CMakeLists.txt [new file with mode: 0644]
rostests/winetests/vbscript/api.vbs [new file with mode: 0644]
rostests/winetests/vbscript/createobj.c [new file with mode: 0644]
rostests/winetests/vbscript/lang.vbs [new file with mode: 0644]
rostests/winetests/vbscript/regexp.vbs [new file with mode: 0644]
rostests/winetests/vbscript/rsrc.rc [new file with mode: 0644]
rostests/winetests/vbscript/run.c [new file with mode: 0644]
rostests/winetests/vbscript/testlist.c [new file with mode: 0644]
rostests/winetests/vbscript/vbscript.c [new file with mode: 0644]
rostests/winetests/vbscript/vbscript_defs.h [new file with mode: 0644]
rostests/winetests/vbscript/vbsregexp55.idl [new file with mode: 0644]

index 7e46e02..450fd38 100644 (file)
@@ -88,6 +88,7 @@ add_subdirectory(user32)
 add_subdirectory(userenv)
 add_subdirectory(usp10)
 add_subdirectory(uxtheme)
+add_subdirectory(vbscript)
 add_subdirectory(version)
 add_subdirectory(windowscodecs)
 add_subdirectory(winhttp)
diff --git a/rostests/winetests/vbscript/CMakeLists.txt b/rostests/winetests/vbscript/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fc6e85c
--- /dev/null
@@ -0,0 +1,24 @@
+
+add_definitions(-D__ROS_LONG64__)
+add_idl_headers(vbscript_wine_test_idlheader vbsregexp55.idl)
+
+list(APPEND SOURCE
+    createobj.c
+    run.c
+    vbscript.c
+    testlist.c
+    rsrc.rc)
+
+list(APPEND vbscript_winetest_rc_deps
+    ${CMAKE_CURRENT_SOURCE_DIR}/api.vbs
+    ${CMAKE_CURRENT_SOURCE_DIR}/lang.vbs
+    ${CMAKE_CURRENT_SOURCE_DIR}/regexp.vbs)
+
+set_source_files_properties(rsrc.rc PROPERTIES OBJECT_DEPENDS "${vbscript_winetest_rc_deps}")
+
+add_executable(vbscript_winetest ${SOURCE})
+target_link_libraries(vbscript_winetest wine)
+set_module_type(vbscript_winetest win32cui)
+add_importlibs(vbscript_winetest ole32 oleaut32 advapi32 msvcrt kernel32 ntdll)
+add_dependencies(vbscript_winetest vbscript_wine_test_idlheader)
+add_cd_file(TARGET vbscript_winetest DESTINATION reactos/bin FOR all)
diff --git a/rostests/winetests/vbscript/api.vbs b/rostests/winetests/vbscript/api.vbs
new file mode 100644 (file)
index 0000000..0aaeefb
--- /dev/null
@@ -0,0 +1,427 @@
+'
+' Copyright 2011 Jacek Caban for CodeWeavers
+'
+' This library is free software; you can redistribute it and/or
+' modify it under the terms of the GNU Lesser General Public
+' License as published by the Free Software Foundation; either
+' version 2.1 of the License, or (at your option) any later version.
+'
+' This library is distributed in the hope that it will be useful,
+' but WITHOUT ANY WARRANTY; without even the implied warranty of
+' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+' Lesser General Public License for more details.
+'
+' You should have received a copy of the GNU Lesser General Public
+' License along with this library; if not, write to the Free Software
+' Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+'
+
+Option Explicit
+
+Dim x
+
+Class EmptyClass
+End Class
+
+Call ok(vbSunday = 1, "vbSunday = " & vbSunday)
+Call ok(getVT(vbSunday) = "VT_I2", "getVT(vbSunday) = " & getVT(vbSunday))
+Call ok(vbMonday = 2, "vbMonday = " & vbMonday)
+Call ok(getVT(vbMonday) = "VT_I2", "getVT(vbMonday) = " & getVT(vbMonday))
+Call ok(vbTuesday = 3, "vbTuesday = " & vbTuesday)
+Call ok(getVT(vbTuesday) = "VT_I2", "getVT(vbTuesday) = " & getVT(vbTuesday))
+Call ok(vbWednesday = 4, "vbWednesday = " & vbWednesday)
+Call ok(getVT(vbWednesday) = "VT_I2", "getVT(vbWednesday) = " & getVT(vbWednesday))
+Call ok(vbThursday = 5, "vbThursday = " & vbThursday)
+Call ok(getVT(vbThursday) = "VT_I2", "getVT(vbThursday) = " & getVT(vbThursday))
+Call ok(vbFriday = 6, "vbFriday = " & vbFriday)
+Call ok(getVT(vbFriday) = "VT_I2", "getVT(vbFriday) = " & getVT(vbFriday))
+Call ok(vbSaturday = 7, "vbSaturday = " & vbSaturday)
+Call ok(getVT(vbSaturday) = "VT_I2", "getVT(vbSaturday) = " & getVT(vbSaturday))
+
+Sub TestConstant(name, val, exval)
+    Call ok(val = exval, name & " =  " & val & " expected " & exval)
+    Call ok(getVT(val) = "VT_I2*", "getVT(" & name & ") = " & getVT(val))
+End Sub
+
+Sub TestConstantI4(name, val, exval)
+    Call ok(val = exval, name & " =  " & val & " expected " & exval)
+    Call ok(getVT(val) = "VT_I4*", "getVT(" & name & ") = " & getVT(val))
+End Sub
+
+Sub TestConstantBSTR(name, val, exval)
+    Call ok(val = exval, name & " =  " & val & " expected " & exval)
+    Call ok(getVT(val) = "VT_BSTR*", "getVT(" & name & ") = " & getVT(val))
+End Sub
+
+TestConstant "vbEmpty", vbEmpty, 0
+TestConstant "vbNull", vbNull, 1
+TestConstant "vbLong", vbLong, 3
+TestConstant "vbSingle", vbSingle, 4
+TestConstant "vbDouble", vbDouble, 5
+TestConstant "vbCurrency", vbCurrency, 6
+TestConstant "vbDate", vbDate, 7
+TestConstant "vbString", vbString, 8
+TestConstant "vbObject", vbObject, 9
+TestConstant "vbError", vbError, 10
+TestConstant "vbBoolean", vbBoolean, 11
+TestConstant "vbVariant", vbVariant, 12
+TestConstant "vbDataObject", vbDataObject, 13
+TestConstant "vbDecimal", vbDecimal, 14
+TestConstant "vbByte", vbByte, 17
+TestConstant "vbArray", vbArray, 8192
+TestConstant "vbCritical", vbCritical, 16
+TestConstant "vbQuestion", vbQuestion, 32
+TestConstant "vbExclamation", vbExclamation, 48
+TestConstant "vbInformation", vbInformation, 64
+TestConstant "vbDefaultButton1", vbDefaultButton1, 0
+TestConstant "vbDefaultButton2", vbDefaultButton2, 256
+TestConstant "vbDefaultButton3", vbDefaultButton3, 512
+TestConstant "vbDefaultButton4", vbDefaultButton4, 768
+TestConstant "vbApplicationModal", vbApplicationModal, 0
+TestConstant "vbSystemModal", vbSystemModal, 4096
+TestConstant "vbUseSystem", vbUseSystem, 0
+TestConstant "vbUseSystemDayOfWeek", vbUseSystemDayOfWeek, 0
+TestConstant "vbFirstJan1", vbFirstJan1, 1
+TestConstant "vbFirstFourDays", vbFirstFourDays, 2
+TestConstant "vbFirstFullWeek", vbFirstFullWeek, 3
+TestConstant "vbTrue", vbTrue, -1
+TestConstant "vbFalse", vbFalse, 0
+TestConstantI4 "vbMsgBoxHelpButton", vbMsgBoxHelpButton, 16384
+TestConstantI4 "vbMsgBoxSetForeground", vbMsgBoxSetForeground, 65536
+TestConstantI4 "vbMsgBoxRight", vbMsgBoxRight, 524288
+TestConstantI4 "vbMsgBoxRtlReading", vbMsgBoxRtlReading, 1048576
+TestConstant "vbUseDefault", vbUseDefault, -2
+TestConstant "vbBinaryCompare", vbBinaryCompare, 0
+TestConstant "vbTextCompare", vbTextCompare, 1
+TestConstant "vbDatabaseCompare", vbDatabaseCompare, 2
+TestConstant "vbGeneralDate", vbGeneralDate, 0
+TestConstant "vbLongDate", vbLongDate, 1
+TestConstant "vbShortDate", vbShortDate, 2
+TestConstant "vbLongTime", vbLongTime, 3
+TestConstant "vbShortTime", vbShortTime, 4
+TestConstantI4 "vbObjectError", vbObjectError, &h80040000&
+TestConstantI4 "vbBlack", vbBlack, 0
+TestConstantI4 "vbBlue", vbBlue, &hff0000&
+TestConstantI4 "vbCyan", vbCyan, &hffff00&
+TestConstantI4 "vbGreen", vbGreen, &h00ff00&
+TestConstantI4 "vbMagenta", vbMagenta, &hff00ff&
+TestConstantI4 "vbRed", vbRed, &h0000ff&
+TestConstantI4 "vbWhite", vbWhite, &hffffff&
+TestConstantI4 "vbYellow", vbYellow, &h00ffff&
+TestConstantBSTR "vbCr", vbCr, Chr(13)
+TestConstantBSTR "vbCrLf", vbCrLf, Chr(13)&Chr(10)
+TestConstantBSTR "vbNewLine", vbNewLine, Chr(13)&Chr(10)
+TestConstantBSTR "vbFormFeed", vbFormFeed, Chr(12)
+TestConstantBSTR "vbLf", vbLf, Chr(10)
+TestConstantBSTR "vbNullChar", vbNullChar, Chr(0)
+TestConstantBSTR "vbNullString", vbNullString, ""
+TestConstantBSTR "vbTab", vbTab, chr(9)
+TestConstantBSTR "vbVerticalTab", vbVerticalTab, chr(11)
+
+Sub TestCStr(arg, exval)
+    dim x
+    x = CStr(arg)
+    Call ok(getVT(x) = "VT_BSTR*", "getVT(x) = " & getVT(x))
+    Call ok(x = exval, "CStr(" & arg & ") = " & x)
+End Sub
+
+TestCStr "test", "test"
+TestCStr 3, "3"
+if isEnglishLang then TestCStr 3.5, "3.5"
+if isEnglishLang then TestCStr true, "True"
+
+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))
+Call ok(Chr(0) <> "", "Chr(0) = """"")
+
+Call ok(isObject(new EmptyClass), "isObject(new EmptyClass) is not true?")
+Set x = new EmptyClass
+Call ok(isObject(x), "isObject(x) is not true?")
+Call ok(isObject(Nothing), "isObject(Nothing) is not true?")
+Call ok(not isObject(true), "isObject(true) is true?")
+Call ok(not isObject(4), "isObject(4) is true?")
+Call ok(not isObject("x"), "isObject(""x"") is true?")
+Call ok(not isObject(Null), "isObject(Null) is true?")
+
+Call ok(not isEmpty(new EmptyClass), "isEmpty(new EmptyClass) is true?")
+Set x = new EmptyClass
+Call ok(not isEmpty(x), "isEmpty(x) is true?")
+x = empty
+Call ok(isEmpty(x), "isEmpty(x) is not true?")
+Call ok(isEmpty(empty), "isEmpty(empty) is not true?")
+Call ok(not isEmpty(Nothing), "isEmpty(Nothing) is not true?")
+Call ok(not isEmpty(true), "isEmpty(true) is true?")
+Call ok(not isEmpty(4), "isEmpty(4) is true?")
+Call ok(not isEmpty("x"), "isEmpty(""x"") is true?")
+Call ok(not isEmpty(Null), "isEmpty(Null) is true?")
+
+Call ok(not isNull(new EmptyClass), "isNull(new EmptyClass) is true?")
+Set x = new EmptyClass
+Call ok(not isNull(x), "isNull(x) is true?")
+x = null
+Call ok(isNull(x), "isNull(x) is not true?")
+Call ok(not isNull(empty), "isNull(empty) is true?")
+Call ok(not isNull(Nothing), "isNull(Nothing) is true?")
+Call ok(not isNull(true), "isNull(true) is true?")
+Call ok(not isNull(4), "isNull(4) is true?")
+Call ok(not isNull("x"), "isNull(""x"") is true?")
+Call ok(isNull(Null), "isNull(Null) is not true?")
+
+Call ok(getVT(err) = "VT_DISPATCH", "getVT(err) = " & getVT(err))
+
+Sub TestHex(x, ex)
+    Call ok(hex(x) = ex, "hex(" & x & ") = " & hex(x) & " expected " & ex)
+End Sub
+
+TestHex 0, "0"
+TestHex 6, "6"
+TestHex 16, "10"
+TestHex &hdeadbeef&, "DEADBEEF"
+TestHex -1, "FFFF"
+TestHex -16, "FFF0"
+TestHex -934859845, "C8472BBB"
+TestHex empty, "0"
+
+Call ok(getVT(hex(null)) = "VT_NULL", "getVT(hex(null)) = " & getVT(hex(null)))
+Call ok(getVT(hex(empty)) = "VT_BSTR", "getVT(hex(empty)) = " & getVT(hex(empty)))
+
+x = InStr(1, "abcd", "bc")
+Call ok(x = 2, "InStr returned " & x)
+
+x = InStr("abcd", "bc")
+Call ok(x = 2, "InStr returned " & x)
+
+x = InStr("abc", "bc")
+Call ok(x = 2, "InStr returned " & x)
+
+x = InStr("abcbc", "bc")
+Call ok(x = 2, "InStr returned " & x)
+
+x = InStr("bcabc", "bc")
+Call ok(x = 1, "InStr returned " & x)
+
+x = InStr(3, "abcd", "bc")
+Call ok(x = 0, "InStr returned " & x)
+
+x = InStr("abcd", "bcx")
+Call ok(x = 0, "InStr returned " & x)
+
+x = InStr(5, "abcd", "bc")
+Call ok(x = 0, "InStr returned " & x)
+
+x = "abcd"
+x = InStr(x, "bc")
+Call ok(x = 2, "InStr returned " & x)
+
+x = InStr("abcd", null)
+Call ok(isNull(x), "InStr returned " & x)
+x = InStr(null, "abcd")
+Call ok(isNull(x), "InStr returned " & x)
+x = InStr(2, null, "abcd")
+Call ok(isNull(x), "InStr returned " & x)
+
+x = InStr(1.3, "abcd", "bc")
+Call ok(x = 2, "InStr returned " & x)
+
+x = InStr(2.3, "abcd", "bc")
+Call ok(x = 2, "InStr returned " & x)
+
+x = InStr(2.6, "abcd", "bc")
+Call ok(x = 0, "InStr returned " & x)
+
+Sub TestMid(str, start, len, ex)
+    x = Mid(str, start, len)
+    Call ok(x = ex, "Mid(" & str & ", " & start & ", " & len & ") = " & x & " expected " & ex)
+End Sub
+
+Sub TestMid2(str, start, ex)
+    x = Mid(str, start)
+    Call ok(x = ex, "Mid(" & str & ", " & start & ") = " & x & " expected " & ex)
+End Sub
+
+TestMid "test", 2, 2, "es"
+TestMid "test", 2, 4, "est"
+TestMid "test", 1, 2, "te"
+TestMid "test", 1, 0, ""
+TestMid "test", 1, 0, ""
+TestMid "test", 5, 2, ""
+TestMid2 "test", 1, "test"
+TestMid2 "test", 2, "est"
+TestMid2 "test", 4, "t"
+TestMid2 "test", 5, ""
+
+Sub TestUCase(str, ex)
+    x = UCase(str)
+    Call ok(x = ex, "UCase(" & str & ") = " & x & " expected " & ex)
+End Sub
+
+TestUCase "test", "TEST"
+TestUCase "123aBC?", "123ABC?"
+TestUCase "", ""
+TestUCase 1, "1"
+if isEnglishLang then TestUCase true, "TRUE"
+TestUCase 0.123, doubleAsString(0.123)
+TestUCase Empty, ""
+Call ok(getVT(UCase(Null)) = "VT_NULL", "getVT(UCase(Null)) = " & getVT(UCase(Null)))
+
+Sub TestLCase(str, ex)
+    x = LCase(str)
+    Call ok(x = ex, "LCase(" & str & ") = " & x & " expected " & ex)
+End Sub
+
+TestLCase "test", "test"
+TestLCase "123aBC?", "123abc?"
+TestLCase "", ""
+TestLCase 1, "1"
+if isEnglishLang then TestLCase true, "true"
+TestLCase 0.123, doubleAsString(0.123)
+TestLCase Empty, ""
+Call ok(getVT(LCase(Null)) = "VT_NULL", "getVT(LCase(Null)) = " & getVT(LCase(Null)))
+
+Call ok(Len("abc") = 3, "Len(abc) = " & Len("abc"))
+Call ok(Len("") = 0, "Len() = " & Len(""))
+Call ok(Len(1) = 1, "Len(1) = " & Len(1))
+Call ok(isNull(Len(null)), "Len(null) = " & Len(null))
+Call ok(Len(empty) = 0, "Len(empty) = " & Len(empty))
+
+Call ok(Space(1) = " ", "Space(1) = " & Space(1) & """")
+Call ok(Space(0) = "", "Space(0) = " & Space(0) & """")
+Call ok(Space(false) = "", "Space(false) = " & Space(false) & """")
+Call ok(Space(5) = "     ", "Space(5) = " & Space(5) & """")
+Call ok(Space(5.2) = "     ", "Space(5.2) = " & Space(5.2) & """")
+Call ok(Space(5.8) = "      ", "Space(5.8) = " & Space(5.8) & """")
+Call ok(Space(5.5) = "      ", "Space(5.5) = " & Space(5.5) & """")
+
+Sub TestStrReverse(str, ex)
+    Call ok(StrReverse(str) = ex, "StrReverse(" & str & ") = " & StrReverse(str))
+End Sub
+
+TestStrReverse "test", "tset"
+TestStrReverse "", ""
+TestStrReverse 123, "321"
+if isEnglishLang then TestStrReverse true, "eurT"
+
+Sub TestLeft(str, len, ex)
+    Call ok(Left(str, len) = ex, "Left(" & str & ", " & len & ") = " & Left(str, len))
+End Sub
+
+TestLeft "test", 2, "te"
+TestLeft "test", 5, "test"
+TestLeft "test", 0, ""
+TestLeft 123, 2, "12"
+if isEnglishLang then TestLeft true, 2, "Tr"
+
+Sub TestRight(str, len, ex)
+    Call ok(Right(str, len) = ex, "Right(" & str & ", " & len & ") = " & Right(str, len))
+End Sub
+
+TestRight "test", 2, "st"
+TestRight "test", 5, "test"
+TestRight "test", 0, ""
+TestRight 123, 2, "23"
+if isEnglishLang then TestRight true, 2, "ue"
+
+Sub TestTrim(str, exstr)
+    Call ok(Trim(str) = exstr, "Trim(" & str & ") = " & Trim(str))
+End Sub
+
+TestTrim "   test    ", "test"
+TestTrim "test    ", "test"
+TestTrim "   test", "test"
+TestTrim "test", "test"
+TestTrim "", ""
+TestTrim 123, "123"
+if isEnglishLang then TestTrim true, "True"
+
+Sub TestLTrim(str, exstr)
+    Call ok(LTrim(str) = exstr, "LTrim(" & str & ") = " & LTrim(str))
+End Sub
+
+TestLTrim "   test    ", "test    "
+TestLTrim "test    ", "test    "
+TestLTrim "   test", "test"
+TestLTrim "test", "test"
+TestLTrim "", ""
+TestLTrim 123, "123"
+if isEnglishLang then TestLTrim true, "True"
+
+Sub TestRound(val, exval, vt)
+    Call ok(Round(val) = exval, "Round(" & val & ") = " & Round(val))
+    Call ok(getVT(Round(val)) = vt, "getVT(Round(" & val & ")) = " & getVT(Round(val)))
+End Sub
+
+Sub TestRTrim(str, exstr)
+    Call ok(RTrim(str) = exstr, "RTrim(" & str & ") = " & RTrim(str))
+End Sub
+
+TestRTrim "   test    ", "   test"
+TestRTrim "test    ", "test"
+TestRTrim "   test", "   test"
+TestRTrim "test", "test"
+TestRTrim "", ""
+TestRTrim 123, "123"
+if isEnglishLang then TestRTrim true, "True"
+
+TestRound 3, 3, "VT_I2"
+TestRound 3.3, 3, "VT_R8"
+TestRound 3.8, 4, "VT_R8"
+TestRound 3.5, 4, "VT_R8"
+TestRound -3.3, -3, "VT_R8"
+TestRound -3.5, -4, "VT_R8"
+TestRound "2", 2, "VT_R8"
+TestRound true, true, "VT_BOOL"
+TestRound false, false, "VT_BOOL"
+
+if isEnglishLang then
+    Call ok(WeekDayName(1) = "Sunday", "WeekDayName(1) = " & WeekDayName(1))
+    Call ok(WeekDayName(3) = "Tuesday", "WeekDayName(3) = " & WeekDayName(3))
+    Call ok(WeekDayName(7) = "Saturday", "WeekDayName(7) = " & WeekDayName(7))
+    Call ok(WeekDayName(1.1) = "Sunday", "WeekDayName(1.1) = " & WeekDayName(1.1))
+    Call ok(WeekDayName(1, false) = "Sunday", "WeekDayName(1, false) = " & WeekDayName(1, false))
+    Call ok(WeekDayName(1, true) = "Sun", "WeekDayName(1, true) = " & WeekDayName(1, true))
+    Call ok(WeekDayName(1, 10) = "Sun", "WeekDayName(1, 10) = " & WeekDayName(1, 10))
+    Call ok(WeekDayName(1, true, 0) = "Sun", "WeekDayName(1, true, 0) = " & WeekDayName(1, true, 0))
+    Call ok(WeekDayName(1, true, 2) = "Mon", "WeekDayName(1, true, 2) = " & WeekDayName(1, true, 2))
+    Call ok(WeekDayName(1, true, 7) = "Sat", "WeekDayName(1, true, 7) = " & WeekDayName(1, true, 7))
+    Call ok(WeekDayName(1, true, 7.1) = "Sat", "WeekDayName(1, true, 7.1) = " & WeekDayName(1, true, 7.1))
+
+    Call ok(MonthName(1) = "January", "MonthName(1) = " & MonthName(1))
+    Call ok(MonthName(12) = "December", "MonthName(12) = " & MonthName(12))
+    Call ok(MonthName(1, 0) = "January", "MonthName(1, 0) = " & MonthName(1, 0))
+    Call ok(MonthName(12, false) = "December", "MonthName(12, false) = " & MonthName(12, false))
+    Call ok(MonthName(1, 10) = "Jan", "MonthName(1, 10) = " & MonthName(1, 10))
+    Call ok(MonthName(12, true) = "Dec", "MonthName(12, true) = " & MonthName(12, true))
+end if
+
+Call ok(getVT(Now()) = "VT_DATE", "getVT(Now()) = " & getVT(Now()))
+
+Call ok(vbOKOnly = 0, "vbOKOnly = " & vbOKOnly)
+Call ok(getVT(vbOKOnly) = "VT_I2", "getVT(vbOKOnly) = " & getVT(vbOKOnly))
+Call ok(vbOKCancel = 1, "vbOKCancel = " & vbOKCancel)
+Call ok(getVT(vbOKCancel) = "VT_I2", "getVT(vbOKCancel) = " & getVT(vbOKCancel))
+Call ok(vbAbortRetryIgnore = 2, "vbAbortRetryIgnore = " & vbAbortRetryIgnore)
+Call ok(getVT(vbAbortRetryIgnore) = "VT_I2", "getVT(vbAbortRetryIgnore) = " & getVT(vbAbortRetryIgnore))
+Call ok(vbYesNoCancel = 3, "vbYesNoCancel = " & vbYesNoCancel)
+Call ok(getVT(vbYesNoCancel) = "VT_I2", "getVT(vbYesNoCancel) = " & getVT(vbYesNoCancel))
+Call ok(vbYesNo = 4, "vbYesNo = " & vbYesNo)
+Call ok(getVT(vbYesNo) = "VT_I2", "getVT(vbYesNo) = " & getVT(vbYesNo))
+Call ok(vbRetryCancel = 5, "vbRetryCancel = " & vbRetryCancel)
+Call ok(getVT(vbRetryCancel) = "VT_I2", "getVT(vbRetryCancel) = " & getVT(vbRetryCancel))
+
+Call ok(vbOK = 1, "vbOK = " & vbOK)
+Call ok(getVT(vbOK) = "VT_I2", "getVT(vbOK) = " & getVT(vbOK))
+Call ok(vbCancel = 2, "vbCancel = " & vbCancel)
+Call ok(getVT(vbCancel) = "VT_I2", "getVT(vbCancel) = " & getVT(vbCancel))
+Call ok(vbAbort = 3, "vbAbort = " & vbAbort)
+Call ok(getVT(vbAbort) = "VT_I2", "getVT(vbAbort) = " & getVT(vbAbort))
+Call ok(vbRetry = 4, "vbRetry = " & vbRetry)
+Call ok(getVT(vbRetry) = "VT_I2", "getVT(vbRetry) = " & getVT(vbRetry))
+Call ok(vbIgnore = 5, "vbIgnore = " & vbIgnore)
+Call ok(getVT(vbIgnore) = "VT_I2", "getVT(vbIgnore) = " & getVT(vbIgnore))
+Call ok(vbYes = 6, "vbYes = " & vbYes)
+Call ok(getVT(vbYes) = "VT_I2", "getVT(vbYes) = " & getVT(vbYes))
+Call ok(vbNo = 7, "vbNo = " & vbNo)
+Call ok(getVT(vbNo) = "VT_I2", "getVT(vbNo) = " & getVT(vbNo))
+
+Call reportSuccess()
diff --git a/rostests/winetests/vbscript/createobj.c b/rostests/winetests/vbscript/createobj.c
new file mode 100644 (file)
index 0000000..bdb9cd6
--- /dev/null
@@ -0,0 +1,1125 @@
+/*
+ * Copyright 2009,2011 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+
+#define COBJMACROS
+#define CONST_VTABLE
+
+#include <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <winnls.h>
+#include <ole2.h>
+#include <dispex.h>
+#include <activscp.h>
+#include <objsafe.h>
+//#include <urlmon.h>
+//#include <mshtmhst.h>
+
+#include <wine/test.h>
+
+#ifdef _WIN64
+
+#define IActiveScriptParse_QueryInterface IActiveScriptParse64_QueryInterface
+#define IActiveScriptParse_Release IActiveScriptParse64_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
+#define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_64_Release
+
+#else
+
+#define IActiveScriptParse_QueryInterface IActiveScriptParse32_QueryInterface
+#define IActiveScriptParse_Release IActiveScriptParse32_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
+#define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_32_Release
+
+#endif
+
+extern const CLSID CLSID_VBScript;
+
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+    expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_EXPECT(func) \
+    do { \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+#define CLEAR_CALLED(func) \
+    expect_ ## func = called_ ## func = FALSE
+
+DEFINE_EXPECT(CreateInstance);
+DEFINE_EXPECT(ProcessUrlAction);
+DEFINE_EXPECT(QueryCustomPolicy);
+DEFINE_EXPECT(reportSuccess);
+DEFINE_EXPECT(Host_QS_SecMgr);
+DEFINE_EXPECT(Caller_QS_SecMgr);
+DEFINE_EXPECT(QI_IObjectWithSite);
+DEFINE_EXPECT(SetSite);
+
+static const WCHAR testW[] = {'t','e','s','t',0};
+
+static HRESULT QS_SecMgr_hres;
+static HRESULT ProcessUrlAction_hres;
+static DWORD ProcessUrlAction_policy;
+static HRESULT CreateInstance_hres;
+static HRESULT QueryCustomPolicy_hres;
+static DWORD QueryCustomPolicy_psize;
+static DWORD QueryCustomPolicy_policy;
+static HRESULT QI_IDispatch_hres;
+static HRESULT QI_IObjectWithSite_hres;
+static HRESULT SetSite_hres;
+
+#define TESTOBJ_CLSID     "{178fc163-f585-4e24-9c13-4bb7faf80646}"
+#define TESTOBJINST_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80647}"
+
+static const GUID CLSID_TestObj =
+    {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x06,0x46}};
+static const GUID CLSID_TestObjInst =
+    {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x06,0x47}};
+
+/* Defined as extern in urlmon.idl, but not exported by uuid.lib */
+const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY =
+    {0x10200490,0xfa38,0x11d0,{0xac,0x0e,0x00,0xa0,0xc9,0xf,0xff,0xc0}};
+
+#define DISPID_TEST_REPORTSUCCESS    0x1000
+
+#define DISPID_GLOBAL_OK             0x2000
+
+#define VB_E_CANNOT_CREATE_OBJ 0x800a01ad
+
+static const char *debugstr_guid(REFIID riid)
+{
+    static char buf[50];
+
+    sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+            riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
+            riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
+            riid->Data4[5], riid->Data4[6], riid->Data4[7]);
+
+    return buf;
+}
+
+static BSTR a2bstr(const char *str)
+{
+    BSTR ret;
+    int len;
+
+    len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+    ret = SysAllocStringLen(NULL, len-1);
+    MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
+
+    return ret;
+}
+
+static int strcmp_wa(LPCWSTR strw, const char *stra)
+{
+    CHAR buf[512];
+    WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), 0, 0);
+    return lstrcmpA(buf, stra);
+}
+
+static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID riid, void **ppv)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *pUnkSite)
+{
+    IServiceProvider *sp;
+    HRESULT hres;
+
+
+    CHECK_EXPECT(SetSite);
+    ok(pUnkSite != NULL, "pUnkSite == NULL\n");
+
+    hres = IUnknown_QueryInterface(pUnkSite, &IID_IServiceProvider, (void**)&sp);
+    ok(hres == S_OK, "Could not get IServiceProvider iface: %08x\n", hres);
+    IServiceProvider_Release(sp);
+
+    return SetSite_hres;
+}
+
+static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, void **ppvSite)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static const IObjectWithSiteVtbl ObjectWithSiteVtbl = {
+    ObjectWithSite_QueryInterface,
+    ObjectWithSite_AddRef,
+    ObjectWithSite_Release,
+    ObjectWithSite_SetSite,
+    ObjectWithSite_GetSite
+};
+
+static IObjectWithSite ObjectWithSite = { &ObjectWithSiteVtbl };
+
+static IObjectWithSite *object_with_site;
+
+static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(riid, &IID_IUnknown)) {
+       *ppv = iface;
+    }else if(IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IDispatchEx)) {
+        if(FAILED(QI_IDispatch_hres))
+            return QI_IDispatch_hres;
+        *ppv = iface;
+    }else if(IsEqualGUID(&IID_IObjectWithSite, riid)) {
+        CHECK_EXPECT(QI_IObjectWithSite);
+        if(FAILED(QI_IObjectWithSite_hres))
+            return QI_IObjectWithSite_hres;
+        *ppv = object_with_site;
+    }else if(IsEqualGUID(&IID_IObjectSafety, riid)) {
+        ok(0, "Unexpected IID_IObjectSafety query\n");
+    }
+
+    return *ppv ? S_OK : E_NOINTERFACE;
+}
+
+static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
+                                              LCID lcid, ITypeInfo **ppTInfo)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
+                                                LPOLESTR *rgszNames, UINT cNames,
+                                                LCID lcid, DISPID *rgDispId)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
+                            REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+                            VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
+{
+    ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Test_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
+{
+    if(!strcmp_wa(bstrName, "reportSuccess")) {
+        ok(grfdex == fdexNameCaseInsensitive, "grfdex = %x\n", grfdex);
+        *pid = DISPID_TEST_REPORTSUCCESS;
+        return S_OK;
+    }
+
+    ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
+        VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+    switch(id) {
+    case DISPID_TEST_REPORTSUCCESS:
+        CHECK_EXPECT(reportSuccess);
+
+        ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
+        ok(pdp->cArgs == 0, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(!pvarRes, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+        break;
+
+    default:
+        ok(0, "unexpected call\n");
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static IDispatchExVtbl testObjVtbl = {
+    DispatchEx_QueryInterface,
+    DispatchEx_AddRef,
+    DispatchEx_Release,
+    DispatchEx_GetTypeInfoCount,
+    DispatchEx_GetTypeInfo,
+    DispatchEx_GetIDsOfNames,
+    DispatchEx_Invoke,
+    Test_GetDispID,
+    Test_InvokeEx,
+    DispatchEx_DeleteMemberByName,
+    DispatchEx_DeleteMemberByDispID,
+    DispatchEx_GetMemberProperties,
+    DispatchEx_GetMemberName,
+    DispatchEx_GetNextDispID,
+    DispatchEx_GetNameSpaceParent
+};
+
+static IDispatchEx testObj = { &testObjVtbl };
+
+static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
+{
+    if(!strcmp_wa(bstrName, "ok")) {
+        ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
+        *pid = DISPID_GLOBAL_OK;
+        return S_OK;
+    }
+
+    ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
+        VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+    switch(id) {
+    case DISPID_GLOBAL_OK:
+        ok(wFlags == INVOKE_FUNC || 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 == 2, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pei != NULL, "pei == NULL\n");
+
+        ok(V_VT(pdp->rgvarg) == VT_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
+        ok(V_VT(pdp->rgvarg+1) == VT_BOOL, "V_VT(psp->rgvargs+1) = %d\n", V_VT(pdp->rgvarg));
+        ok(V_BOOL(pdp->rgvarg+1), "%s\n", wine_dbgstr_w(V_BSTR(pdp->rgvarg)));
+        break;
+
+    default:
+        ok(0, "unexpected call\n");
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static IDispatchExVtbl globalObjVtbl = {
+    DispatchEx_QueryInterface,
+    DispatchEx_AddRef,
+    DispatchEx_Release,
+    DispatchEx_GetTypeInfoCount,
+    DispatchEx_GetTypeInfo,
+    DispatchEx_GetIDsOfNames,
+    DispatchEx_Invoke,
+    Global_GetDispID,
+    Global_InvokeEx,
+    DispatchEx_DeleteMemberByName,
+    DispatchEx_DeleteMemberByDispID,
+    DispatchEx_GetMemberProperties,
+    DispatchEx_GetMemberName,
+    DispatchEx_GetNextDispID,
+    DispatchEx_GetNameSpaceParent
+};
+
+static IDispatchEx globalObj = { &globalObjVtbl };
+
+static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    /* TODO: IClassFactoryEx */
+    *ppv = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
+{
+    CHECK_EXPECT(CreateInstance);
+
+    ok(!outer, "outer = %p\n", outer);
+    ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
+
+    if(SUCCEEDED(CreateInstance_hres))
+        *ppv = &testObj;
+    return CreateInstance_hres;
+}
+
+static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    ok(0, "unexpected call\n");
+    return S_OK;
+}
+
+static const IClassFactoryVtbl ClassFactoryVtbl = {
+    ClassFactory_QueryInterface,
+    ClassFactory_AddRef,
+    ClassFactory_Release,
+    ClassFactory_CreateInstance,
+    ClassFactory_LockServer
+};
+
+static IClassFactory activex_cf = { &ClassFactoryVtbl };
+
+static HRESULT WINAPI InternetHostSecurityManager_QueryInterface(IInternetHostSecurityManager *iface, REFIID riid, void **ppv)
+{
+    ok(0, "unexpected call\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI InternetHostSecurityManager_AddRef(IInternetHostSecurityManager *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI InternetHostSecurityManager_Release(IInternetHostSecurityManager *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI InternetHostSecurityManager_GetSecurityId(IInternetHostSecurityManager *iface,  BYTE *pbSecurityId,
+        DWORD *pcbSecurityId, DWORD_PTR dwReserved)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI InternetHostSecurityManager_ProcessUrlAction(IInternetHostSecurityManager *iface, DWORD dwAction,
+        BYTE *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwFlags, DWORD dwReserved)
+{
+    CHECK_EXPECT(ProcessUrlAction);
+
+    ok(dwAction == URLACTION_ACTIVEX_RUN, "dwAction = %x\n", dwAction);
+    ok(pPolicy != NULL, "pPolicy == NULL\n");
+    ok(cbPolicy == sizeof(DWORD), "cbPolicy = %d\n", cbPolicy);
+    ok(pContext != NULL, "pContext == NULL\n");
+    ok(cbContext == sizeof(GUID), "cbContext = %d\n", cbContext);
+    ok(IsEqualGUID(pContext, &CLSID_TestObj), "pContext = %s\n", debugstr_guid((const IID*)pContext));
+    ok(!dwFlags, "dwFlags = %x\n", dwFlags);
+    ok(!dwReserved, "dwReserved = %x\n", dwReserved);
+
+    if(SUCCEEDED(ProcessUrlAction_hres))
+        *(DWORD*)pPolicy = ProcessUrlAction_policy;
+    return ProcessUrlAction_hres;
+}
+
+static HRESULT WINAPI InternetHostSecurityManager_QueryCustomPolicy(IInternetHostSecurityManager *iface, REFGUID guidKey,
+        BYTE **ppPolicy, DWORD *pcbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwReserved)
+{
+    const struct CONFIRMSAFETY *cs = (const struct CONFIRMSAFETY*)pContext;
+    DWORD *ret;
+
+    CHECK_EXPECT(QueryCustomPolicy);
+
+    ok(IsEqualGUID(&GUID_CUSTOM_CONFIRMOBJECTSAFETY, guidKey), "guidKey = %s\n", debugstr_guid(guidKey));
+
+    ok(ppPolicy != NULL, "ppPolicy == NULL\n");
+    ok(pcbPolicy != NULL, "pcbPolicy == NULL\n");
+    ok(pContext != NULL, "pContext == NULL\n");
+    ok(cbContext == sizeof(struct CONFIRMSAFETY), "cbContext = %d\n", cbContext);
+    ok(!dwReserved, "dwReserved = %x\n", dwReserved);
+
+    /* TODO: CLSID */
+    ok(cs->pUnk != NULL, "cs->pUnk == NULL\n");
+    ok(!cs->dwFlags, "dwFlags = %x\n", cs->dwFlags);
+
+    if(FAILED(QueryCustomPolicy_hres))
+        return QueryCustomPolicy_hres;
+
+    ret = CoTaskMemAlloc(QueryCustomPolicy_psize);
+    *ppPolicy = (BYTE*)ret;
+    *pcbPolicy = QueryCustomPolicy_psize;
+    memset(ret, 0, QueryCustomPolicy_psize);
+    if(QueryCustomPolicy_psize >= sizeof(DWORD))
+        *ret = QueryCustomPolicy_policy;
+
+    return QueryCustomPolicy_hres;
+}
+
+static const IInternetHostSecurityManagerVtbl InternetHostSecurityManagerVtbl = {
+    InternetHostSecurityManager_QueryInterface,
+    InternetHostSecurityManager_AddRef,
+    InternetHostSecurityManager_Release,
+    InternetHostSecurityManager_GetSecurityId,
+    InternetHostSecurityManager_ProcessUrlAction,
+    InternetHostSecurityManager_QueryCustomPolicy
+};
+
+static IInternetHostSecurityManager InternetHostSecurityManager = { &InternetHostSecurityManagerVtbl };
+
+static IServiceProvider ServiceProvider;
+
+static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
+{
+    ok(0, "unexpected call\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
+        REFGUID guidService, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(&SID_GetCaller, guidService))
+        return E_NOINTERFACE;
+
+    if(IsEqualGUID(&SID_SInternetHostSecurityManager, guidService)) {
+        if(iface == &ServiceProvider)
+            CHECK_EXPECT(Host_QS_SecMgr);
+        else
+            CHECK_EXPECT(Caller_QS_SecMgr);
+        ok(IsEqualGUID(&IID_IInternetHostSecurityManager, riid), "unexpected riid %s\n", debugstr_guid(riid));
+        if(SUCCEEDED(QS_SecMgr_hres))
+            *ppv = &InternetHostSecurityManager;
+        return QS_SecMgr_hres;
+    }
+
+    ok(0, "unexpected service %s\n", debugstr_guid(guidService));
+    return E_NOINTERFACE;
+}
+
+static IServiceProviderVtbl ServiceProviderVtbl = {
+    ServiceProvider_QueryInterface,
+    ServiceProvider_AddRef,
+    ServiceProvider_Release,
+    ServiceProvider_QueryService
+};
+
+static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
+
+static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        *ppv = iface;
+    }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
+        *ppv = iface;
+    }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
+        *ppv = &ServiceProvider;
+    }else {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
+{
+    *plcid = GetUserDefaultLCID();
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
+        DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
+{
+    ok(dwReturnMask == SCRIPTINFO_IUNKNOWN, "unexpected dwReturnMask %x\n", dwReturnMask);
+    ok(!ppti, "ppti != NULL\n");
+    ok(!strcmp_wa(pstrName, "test"), "pstrName = %s\n", wine_dbgstr_w(pstrName));
+
+    *ppiunkItem = (IUnknown*)&globalObj;
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
+        const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
+{
+    return E_NOTIMPL;
+}
+
+static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
+    ActiveScriptSite_QueryInterface,
+    ActiveScriptSite_AddRef,
+    ActiveScriptSite_Release,
+    ActiveScriptSite_GetLCID,
+    ActiveScriptSite_GetItemInfo,
+    ActiveScriptSite_GetDocVersionString,
+    ActiveScriptSite_OnScriptTerminate,
+    ActiveScriptSite_OnStateChange,
+    ActiveScriptSite_OnScriptError,
+    ActiveScriptSite_OnEnterScript,
+    ActiveScriptSite_OnLeaveScript
+};
+
+static IActiveScriptSite ActiveScriptSite = { &ActiveScriptSiteVtbl };
+
+static void set_safety_options(IUnknown *unk, BOOL use_sec_mgr)
+{
+    IObjectSafety *safety;
+    DWORD supported, enabled, options_all, options_set;
+    HRESULT hres;
+
+    hres = IUnknown_QueryInterface(unk, &IID_IObjectSafety, (void**)&safety);
+    ok(hres == S_OK, "Could not get IObjectSafety: %08x\n", hres);
+    if(FAILED(hres))
+        return;
+
+    options_all = INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER;
+    if(use_sec_mgr)
+        options_set = options_all;
+    else
+        options_set = INTERFACE_USES_DISPEX;
+
+    hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, options_all, options_set);
+    ok(hres == S_OK, "SetInterfaceSafetyOptions failed: %08x\n", hres);
+
+    supported = enabled = 0xdeadbeef;
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported, &enabled);
+    ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres);
+    ok(supported == options_all, "supported=%x, expected %x\n", supported, options_all);
+    ok(enabled == options_set, "enabled=%x, expected %x\n", enabled, options_set);
+
+    IObjectSafety_Release(safety);
+}
+
+#define parse_script_a(p,s) _parse_script_a(__LINE__,p,s)
+static void _parse_script_a(unsigned line, IActiveScriptParse *parser, const char *script)
+{
+    BSTR str;
+    HRESULT hres;
+
+    str = a2bstr(script);
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    SysFreeString(str);
+    ok_(__FILE__,line)(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+}
+
+static HRESULT parse_script_ae(IActiveScriptParse *parser, const char *script)
+{
+    BSTR str;
+    HRESULT hres;
+
+    str = a2bstr(script);
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    SysFreeString(str);
+
+    return hres;
+}
+
+static IActiveScriptParse *create_script(BOOL use_sec_mgr)
+{
+    IActiveScriptParse *parser;
+    IActiveScript *script;
+    HRESULT hres;
+
+    QS_SecMgr_hres = S_OK;
+    ProcessUrlAction_hres = S_OK;
+    ProcessUrlAction_policy = URLPOLICY_ALLOW;
+    CreateInstance_hres = S_OK;
+    QueryCustomPolicy_hres = S_OK;
+    QueryCustomPolicy_psize = sizeof(DWORD);
+    QueryCustomPolicy_policy = URLPOLICY_ALLOW;
+    QI_IDispatch_hres = S_OK;
+    QI_IObjectWithSite_hres = S_OK;
+    SetSite_hres = S_OK;
+
+    hres = CoCreateInstance(&CLSID_VBScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IActiveScript, (void**)&script);
+    ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
+    if(FAILED(hres))
+        return NULL;
+
+    set_safety_options((IUnknown*)script, use_sec_mgr);
+
+    hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
+
+    hres = IActiveScriptParse_InitNew(parser);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+
+    hres = IActiveScript_AddNamedItem(script, testW,
+            SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
+    ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
+
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
+
+    IActiveScript_Release(script);
+
+    return parser;
+}
+
+static void test_CreateObject(void)
+{
+    IActiveScriptParse *parser;
+    HRESULT hres;
+
+    parser = create_script(TRUE);
+
+    SET_EXPECT(Host_QS_SecMgr);
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QueryCustomPolicy);
+    SET_EXPECT(QI_IObjectWithSite);
+    SET_EXPECT(reportSuccess);
+    parse_script_a(parser, "Call CreateObject(\"Wine.Test\").reportSuccess()");
+    CHECK_CALLED(Host_QS_SecMgr);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QueryCustomPolicy);
+    CHECK_CALLED(QI_IObjectWithSite);
+    CHECK_CALLED(reportSuccess);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.TestABC\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+    QS_SecMgr_hres = E_NOINTERFACE;
+
+    SET_EXPECT(Host_QS_SecMgr);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(Host_QS_SecMgr);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+    ProcessUrlAction_hres = E_FAIL;
+
+    SET_EXPECT(Host_QS_SecMgr);
+    SET_EXPECT(ProcessUrlAction);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(Host_QS_SecMgr);
+    CHECK_CALLED(ProcessUrlAction);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+    ProcessUrlAction_policy = URLPOLICY_DISALLOW;
+
+    SET_EXPECT(Host_QS_SecMgr);
+    SET_EXPECT(ProcessUrlAction);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(Host_QS_SecMgr);
+    CHECK_CALLED(ProcessUrlAction);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+    CreateInstance_hres = E_FAIL;
+
+    SET_EXPECT(Host_QS_SecMgr);
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(Host_QS_SecMgr);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+    QueryCustomPolicy_hres = E_FAIL;
+
+    SET_EXPECT(Host_QS_SecMgr);
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QueryCustomPolicy);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(Host_QS_SecMgr);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QueryCustomPolicy);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+    QueryCustomPolicy_psize = 6;
+
+    SET_EXPECT(Host_QS_SecMgr);
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QueryCustomPolicy);
+    SET_EXPECT(QI_IObjectWithSite);
+    SET_EXPECT(reportSuccess);
+    parse_script_a(parser, "Call CreateObject(\"Wine.Test\").reportSuccess()");
+    CHECK_CALLED(Host_QS_SecMgr);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QueryCustomPolicy);
+    CHECK_CALLED(QI_IObjectWithSite);
+    CHECK_CALLED(reportSuccess);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+    QueryCustomPolicy_policy = URLPOLICY_DISALLOW;
+
+    SET_EXPECT(Host_QS_SecMgr);
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QueryCustomPolicy);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(Host_QS_SecMgr);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QueryCustomPolicy);
+
+    QueryCustomPolicy_psize = 6;
+
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QueryCustomPolicy);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QueryCustomPolicy);
+
+    QueryCustomPolicy_policy = URLPOLICY_ALLOW;
+    QueryCustomPolicy_psize = 3;
+
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QueryCustomPolicy);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QueryCustomPolicy);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(FALSE);
+
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QI_IObjectWithSite);
+    SET_EXPECT(reportSuccess);
+    parse_script_a(parser, "Call CreateObject(\"Wine.Test\").reportSuccess()");
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QI_IObjectWithSite);
+    CHECK_CALLED(reportSuccess);
+
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(TRUE);
+    object_with_site = &ObjectWithSite;
+
+    SET_EXPECT(Host_QS_SecMgr);
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QueryCustomPolicy);
+    SET_EXPECT(QI_IObjectWithSite);
+    SET_EXPECT(SetSite);
+    SET_EXPECT(reportSuccess);
+    parse_script_a(parser, "Call CreateObject(\"Wine.Test\").reportSuccess()");
+    CHECK_CALLED(Host_QS_SecMgr);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QueryCustomPolicy);
+    CHECK_CALLED(QI_IObjectWithSite);
+    CHECK_CALLED(SetSite);
+    CHECK_CALLED(reportSuccess);
+
+    SetSite_hres = E_FAIL;
+    SET_EXPECT(ProcessUrlAction);
+    SET_EXPECT(CreateInstance);
+    SET_EXPECT(QueryCustomPolicy);
+    SET_EXPECT(QI_IObjectWithSite);
+    SET_EXPECT(SetSite);
+    hres = parse_script_ae(parser, "Call CreateObject(\"Wine.Test\")");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    CHECK_CALLED(ProcessUrlAction);
+    CHECK_CALLED(CreateInstance);
+    CHECK_CALLED(QueryCustomPolicy);
+    CHECK_CALLED(QI_IObjectWithSite);
+    CHECK_CALLED(SetSite);
+
+    IActiveScriptParse_Release(parser);
+}
+
+static void test_GetObject(void)
+{
+    IActiveScriptParse *parser;
+    HRESULT hres;
+
+    /* Never allowed with security manager */
+    parser = create_script(TRUE);
+    hres = parse_script_ae(parser, "Call GetObject(\"clsid:" TESTOBJINST_CLSID "\").reportSuccess()");
+    ok(hres == VB_E_CANNOT_CREATE_OBJ, "hres = %08x\n", hres);
+    IActiveScriptParse_Release(parser);
+
+    parser = create_script(FALSE);
+
+    SET_EXPECT(QI_IObjectWithSite);
+    SET_EXPECT(SetSite);
+    SET_EXPECT(reportSuccess);
+    hres = parse_script_ae(parser, "Call GetObject(\"clsid:" TESTOBJINST_CLSID "\").reportSuccess()");
+    if(hres == 0x8007007e) { /* Workaround for broken win2k */
+        win_skip("got unexpected error %08x\n", hres);
+        CLEAR_CALLED(QI_IObjectWithSite);
+        CLEAR_CALLED(SetSite);
+        CLEAR_CALLED(reportSuccess);
+        IActiveScriptParse_Release(parser);
+        return;
+    }
+    CHECK_CALLED(QI_IObjectWithSite);
+    CHECK_CALLED(SetSite);
+    CHECK_CALLED(reportSuccess);
+
+    SetSite_hres = E_FAIL;
+    SET_EXPECT(QI_IObjectWithSite);
+    SET_EXPECT(SetSite);
+    hres = parse_script_ae(parser, "Call GetObject(\"clsid:" TESTOBJINST_CLSID "\").reportSuccess()");
+    ok(hres == E_FAIL, "hres = %08x\n", hres);
+    CHECK_CALLED(QI_IObjectWithSite);
+    CHECK_CALLED(SetSite);
+
+    QI_IObjectWithSite_hres = E_NOINTERFACE;
+    SET_EXPECT(QI_IObjectWithSite);
+    SET_EXPECT(reportSuccess);
+    parse_script_a(parser, "Call GetObject(\"clsid:" TESTOBJINST_CLSID "\").reportSuccess()");
+    CHECK_CALLED(QI_IObjectWithSite);
+    CHECK_CALLED(reportSuccess);
+
+    IActiveScriptParse_Release(parser);
+
+    /* Invalid moniker */
+    parser = create_script(FALSE);
+    hres = parse_script_ae(parser, "Call GetObject(\"nonexistent:test\").reportSuccess()");
+    ok(hres == MK_E_SYNTAX, "hres = %08x\n", hres);
+    IActiveScriptParse_Release(parser);
+}
+
+static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
+{
+    HKEY hkey;
+    DWORD res;
+
+    if(!init) {
+        RegDeleteKey(HKEY_CLASSES_ROOT, key_name);
+        return TRUE;
+    }
+
+    res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey);
+    if(res != ERROR_SUCCESS)
+        return FALSE;
+
+    if(def_value)
+        res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value));
+
+    RegCloseKey(hkey);
+
+    return res == ERROR_SUCCESS;
+}
+
+static BOOL init_registry(BOOL init)
+{
+    return init_key("Wine.Test\\CLSID", TESTOBJ_CLSID, init);
+}
+
+static BOOL register_activex(void)
+{
+    DWORD regid;
+    HRESULT hres;
+
+    if(!init_registry(TRUE)) {
+        init_registry(FALSE);
+        return FALSE;
+    }
+
+    hres = CoRegisterClassObject(&CLSID_TestObj, (IUnknown *)&activex_cf,
+                                 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
+    ok(hres == S_OK, "Could not register script engine: %08x\n", hres);
+
+    hres = CoRegisterClassObject(&CLSID_TestObjInst, (IUnknown *)&testObj,
+                                 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
+    ok(hres == S_OK, "Could not register script engine: %08x\n", hres);
+
+    return TRUE;
+}
+
+static BOOL check_vbscript(void)
+{
+    IActiveScriptParseProcedure2 *vbscript;
+    HRESULT hres;
+
+    hres = CoCreateInstance(&CLSID_VBScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IActiveScriptParseProcedure2, (void**)&vbscript);
+    if(SUCCEEDED(hres))
+        IActiveScriptParseProcedure2_Release(vbscript);
+
+    return hres == S_OK;
+}
+
+
+START_TEST(createobj)
+{
+    CoInitialize(NULL);
+
+    if(check_vbscript()) {
+        register_activex();
+
+        test_CreateObject();
+        test_GetObject();
+
+        init_registry(FALSE);
+    }else {
+        win_skip("Broken engine, probably too old\n");
+    }
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/vbscript/lang.vbs b/rostests/winetests/vbscript/lang.vbs
new file mode 100644 (file)
index 0000000..8cffc7f
--- /dev/null
@@ -0,0 +1,975 @@
+'
+' Copyright 2011 Jacek Caban for CodeWeavers
+'
+' This library is free software; you can redistribute it and/or
+' modify it under the terms of the GNU Lesser General Public
+' License as published by the Free Software Foundation; either
+' version 2.1 of the License, or (at your option) any later version.
+'
+' This library is distributed in the hope that it will be useful,
+' but WITHOUT ANY WARRANTY; without even the implied warranty of
+' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+' Lesser General Public License for more details.
+'
+' You should have received a copy of the GNU Lesser General Public
+' License along with this library; if not, write to the Free Software
+' Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+'
+
+Option Explicit
+
+dim x, y, z
+
+call ok(true, "true is not true?")
+ok true, "true is not true?"
+call ok((true), "true is not true?")
+
+ok not false, "not false but not true?"
+ok not not true, "not not true but not true?"
+
+Call ok(true = true, "true = true is false")
+Call ok(false = false, "false = false is false")
+Call ok(not (true = false), "true = false is true")
+Call ok("x" = "x", """x"" = ""x"" is false")
+Call ok(empty = empty, "empty = empty is false")
+Call ok(empty = "", "empty = """" is false")
+Call ok(0 = 0.0, "0 <> 0.0")
+Call ok(16 = &h10&, "16 <> &h10&")
+Call ok(010 = 10, "010 <> 10")
+Call ok(10. = 10, "10. <> 10")
+Call ok(&hffFFffFF& = -1, "&hffFFffFF& <> -1")
+Call ok(&hffFFffFF& = -1, "&hffFFffFF& <> -1")
+Call ok(--1 = 1, "--1 = " & --1)
+Call ok(-empty = 0, "-empty = " & (-empty))
+Call ok(true = -1, "! true = -1")
+Call ok(false = 0, "false <> 0")
+Call ok(&hff = 255, "&hff <> 255")
+Call ok(&Hff = 255, "&Hff <> 255")
+
+x = "xx"
+Call ok(x = "xx", "x = " & x & " expected ""xx""")
+
+Call ok(true <> false, "true <> false is false")
+Call ok(not (true <> true), "true <> true is true")
+Call ok(not ("x" <> "x"), """x"" <> ""x"" is true")
+Call ok(not (empty <> empty), "empty <> empty is true")
+Call ok(x <> "x", "x = ""x""")
+Call ok("true" <> true, """true"" = true is true")
+
+Call ok("" = true = false, """"" = true = false is false")
+Call ok(not(false = true = ""), "false = true = """" is true")
+Call ok(not (false = false <> false = false), "false = false <> false = false is true")
+Call ok(not ("" <> false = false), """"" <> false = false is true")
+
+Call ok(getVT(false) = "VT_BOOL", "getVT(false) is not VT_BOOL")
+Call ok(getVT(true) = "VT_BOOL", "getVT(true) is not VT_BOOL")
+Call ok(getVT("") = "VT_BSTR", "getVT("""") is not VT_BSTR")
+Call ok(getVT("test") = "VT_BSTR", "getVT(""test"") is not VT_BSTR")
+Call ok(getVT(Empty) = "VT_EMPTY", "getVT(Empty) is not VT_EMPTY")
+Call ok(getVT(null) = "VT_NULL", "getVT(null) is not VT_NULL")
+Call ok(getVT(0) = "VT_I2", "getVT(0) is not VT_I2")
+Call ok(getVT(1) = "VT_I2", "getVT(1) is not VT_I2")
+Call ok(getVT(0.5) = "VT_R8", "getVT(0.5) is not VT_R8")
+Call ok(getVT(0.0) = "VT_R8", "getVT(0.0) is not VT_R8")
+Call ok(getVT(2147483647) = "VT_I4", "getVT(2147483647) is not VT_I4")
+Call ok(getVT(2147483648) = "VT_R8", "getVT(2147483648) is not VT_R8")
+Call ok(getVT(&h10&) = "VT_I2", "getVT(&h10&) is not VT_I2")
+Call ok(getVT(&h10000&) = "VT_I4", "getVT(&h10000&) is not VT_I4")
+Call ok(getVT(&H10000&) = "VT_I4", "getVT(&H10000&) is not VT_I4")
+Call ok(getVT(&hffFFffFF&) = "VT_I2", "getVT(&hffFFffFF&) is not VT_I2")
+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(getVT(false or true) = "VT_BOOL", "getVT(false) is not VT_BOOL")
+x = "x"
+Call ok(getVT(x) = "VT_BSTR*", "getVT(x) is not VT_BSTR*")
+x = 0.0
+Call ok(getVT(x) = "VT_R8*", "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))
+Call ok("ab " & empty = "ab ", """ab"" & empty = " & ("ab " & empty))
+Call ok(1 & 100000 = "1100000", "1 & 100000 = " & (1 & 100000))
+Call ok("ab" & x = "abxx", """ab"" & x = " & ("ab"&x))
+
+if(isEnglishLang) then
+    Call ok("" & true = "True", """"" & true = " & true)
+    Call ok(true & false = "TrueFalse", "true & false = " & (true & false))
+end if
+
+call ok(true and true, "true and true is not true")
+call ok(true and not false, "true and not false is not true")
+call ok(not (false and true), "not (false and true) is not true")
+call ok(getVT(null and true) = "VT_NULL", "getVT(null and true) = " & getVT(null and true))
+
+call ok(false or true, "false or uie is false?")
+call ok(not (false or false), "false or false is not false?")
+call ok(false and false or true, "false and false or true is false?")
+call ok(true or false and false, "true or false and false is false?")
+call ok(null or true, "null or true is false")
+
+call ok(true xor false, "true xor false is false?")
+call ok(not (false xor false), "false xor false is true?")
+call ok(not (true or false xor true), "true or false xor true is true?")
+call ok(not (true xor false or true), "true xor false or true is true?")
+
+call ok(false eqv false, "false does not equal false?")
+call ok(not (false eqv true), "false equals true?")
+call ok(getVT(false eqv null) = "VT_NULL", "getVT(false eqv null) = " & getVT(false eqv null))
+
+call ok(true imp true, "true does not imp true?")
+call ok(false imp false, "false does not imp false?")
+call ok(not (true imp false), "true imp false?")
+call ok(false imp null, "false imp null is false?")
+
+Call ok(2 >= 1, "! 2 >= 1")
+Call ok(2 >= 2, "! 2 >= 2")
+Call ok(not(true >= 2), "true >= 2 ?")
+Call ok(2 > 1, "! 2 > 1")
+Call ok(false > true, "! false < true")
+Call ok(0 > true, "! 0 > true")
+Call ok(not (true > 0), "true > 0")
+Call ok(not (0 > 1 = 1), "0 > 1 = 1")
+Call ok(1 < 2, "! 1 < 2")
+Call ok(1 = 1 < 0, "! 1 = 1 < 0")
+Call ok(1 <= 2, "! 1 <= 2")
+Call ok(2 <= 2, "! 2 <= 2")
+
+Call ok(isNull(0 = null), "'(0 = null)' is not null")
+Call ok(isNull(null = 1), "'(null = 1)' is not null")
+Call ok(isNull(0 > null), "'(0 > null)' is not null")
+Call ok(isNull(null > 1), "'(null > 1)' is not null")
+Call ok(isNull(0 < null), "'(0 < null)' is not null")
+Call ok(isNull(null < 1), "'(null < 1)' is not null")
+Call ok(isNull(0 <> null), "'(0 <> null)' is not null")
+Call ok(isNull(null <> 1), "'(null <> 1)' is not null")
+Call ok(isNull(0 >= null), "'(0 >= null)' is not null")
+Call ok(isNull(null >= 1), "'(null >= 1)' is not null")
+Call ok(isNull(0 <= null), "'(0 <= null)' is not null")
+Call ok(isNull(null <= 1), "'(null <= 1)' is not null")
+
+x = 3
+Call ok(2+2 = 4, "2+2 = " & (2+2))
+Call ok(false + 6 + true = 5, "false + 6 + true <> 5")
+Call ok(getVT(2+null) = "VT_NULL", "getVT(2+null) = " & getVT(2+null))
+Call ok(2+empty = 2, "2+empty = " & (2+empty))
+Call ok(x+x = 6, "x+x = " & (x+x))
+
+Call ok(5-1 = 4, "5-1 = " & (5-1))
+Call ok(3+5-true = 9, "3+5-true <> 9")
+Call ok(getVT(2-null) = "VT_NULL", "getVT(2-null) = " & getVT(2-null))
+Call ok(2-empty = 2, "2-empty = " & (2-empty))
+Call ok(2-x = -1, "2-x = " & (2-x))
+
+Call ok(9 Mod 6 = 3, "9 Mod 6 = " & (9 Mod 6))
+Call ok(11.6 Mod 5.5 = False, "11.6 Mod 5.5 = " & (11.6 Mod 5.5 = 0.6))
+Call ok(7 Mod 4+2 = 5, "7 Mod 4+2 <> 5")
+Call ok(getVT(2 mod null) = "VT_NULL", "getVT(2 mod null) = " & getVT(2 mod null))
+Call ok(getVT(null mod 2) = "VT_NULL", "getVT(null mod 2) = " & getVT(null mod 2))
+'FIXME: Call ok(empty mod 2 = 0, "empty mod 2 = " & (empty mod 2))
+
+Call ok(5 \ 2 = 2, "5 \ 2 = " & (5\2))
+Call ok(4.6 \ 1.5 = 2, "4.6 \ 1.5 = " & (4.6\1.5))
+Call ok(4.6 \ 1.49 = 5, "4.6 \ 1.49 = " & (4.6\1.49))
+Call ok(2+3\4 = 2, "2+3\4 = " & (2+3\4))
+
+Call ok(2*3 = 6, "2*3 = " & (2*3))
+Call ok(3/2 = 1.5, "3/2 = " & (3/2))
+Call ok(5\4/2 = 2, "5\4/2 = " & (5\2/1))
+Call ok(12/3\2 = 2, "12/3\2 = " & (12/3\2))
+
+Call ok(2^3 = 8, "2^3 = " & (2^3))
+Call ok(2^3^2 = 64, "2^3^2 = " & (2^3^2))
+Call ok(-3^2 = 9, "-3^2 = " & (-3^2))
+Call ok(2*3^2 = 18, "2*3^2 = " & (2*3^2))
+
+x =_
+    3
+x _
+    = 3
+
+x = 3
+
+if true then y = true : x = y
+ok x, "x is false"
+
+x = true : if false then x = false
+ok x, "x is false, if false called?"
+
+if not false then x = true
+ok x, "x is false, if not false not called?"
+
+if not false then x = "test" : x = true
+ok x, "x is false, if not false not called?"
+
+if false then x = y : call ok(false, "if false .. : called")
+
+if false then x = y : call ok(false, "if false .. : called") else x = "else"
+Call ok(x = "else", "else not called?")
+
+if true then x = y else y = x : Call ok(false, "in else?")
+
+if false then :
+
+if false then x = y : if true then call ok(false, "embedded if called")
+
+if false then x=1 else x=2 end if
+
+if false then
+    ok false, "if false called"
+end if
+
+x = true
+if x then
+    x = false
+end if
+Call ok(not x, "x is false, if not evaluated?")
+
+x = false
+If false Then
+   Call ok(false, "inside if false")
+Else
+   x = true
+End If
+Call ok(x, "else not called?")
+
+x = false
+If false Then
+   Call ok(false, "inside if false")
+ElseIf not True Then
+   Call ok(false, "inside elseif not true")
+Else
+   x = true
+End If
+Call ok(x, "else not called?")
+
+x = false
+If false Then
+   Call ok(false, "inside if false")
+   x = 1
+   y = 10+x
+ElseIf not False Then
+   x = true
+Else
+   Call ok(false, "inside else not true")
+End If
+Call ok(x, "elseif not called?")
+
+x = false
+If false Then
+   Call ok(false, "inside if false")
+ElseIf not False Then
+   x = true
+End If
+Call ok(x, "elseif not called?")
+
+x = false
+if 1 then x = true
+Call ok(x, "if 1 not run?")
+
+x = false
+if &h10000& then x = true
+Call ok(x, "if &h10000& not run?")
+
+x = false
+y = false
+while not (x and y)
+    if x then
+        y = true
+    end if
+    x = true
+wend
+call ok((x and y), "x or y is false after while")
+
+if false then
+' empty body
+end if
+
+if false then
+    x = false
+elseif true then
+' empty body
+end if
+
+if false then
+    x = false
+else
+' empty body
+end if
+
+while false
+wend
+
+x = false
+y = false
+do while not (x and y)
+    if x then
+        y = true
+    end if
+    x = true
+loop
+call ok((x and y), "x or y is false after while")
+
+do while false
+loop
+
+do while true
+    exit do
+    ok false, "exit do didn't work"
+loop
+
+x = false
+y = false
+do until x and y
+    if x then
+        y = true
+    end if
+    x = true
+loop
+call ok((x and y), "x or y is false after do until")
+
+do until true
+loop
+
+do until false
+    exit do
+    ok false, "exit do didn't work"
+loop
+
+x = false
+do
+    if x then exit do
+    x = true
+loop
+call ok(x, "x is false after do..loop?")
+
+x = false
+y = false
+do
+    if x then
+        y = true
+    end if
+    x = true
+loop until x and y
+call ok((x and y), "x or y is false after while")
+
+do
+loop until true
+
+do
+    exit do
+    ok false, "exit do didn't work"
+loop until false
+
+x = false
+y = false
+do
+    if x then
+        y = true
+    end if
+    x = true
+loop while not (x and y)
+call ok((x and y), "x or y is false after while")
+
+do
+loop while false
+
+do
+    exit do
+    ok false, "exit do didn't work"
+loop while true
+
+y = "for1:"
+for x = 5 to 8
+    y = y & " " & x
+next
+Call ok(y = "for1: 5 6 7 8", "y = " & y)
+
+y = "for2:"
+for x = 5 to 8 step 2
+    y = y & " " & x
+next
+Call ok(y = "for2: 5 7", "y = " & y)
+
+y = "for3:"
+x = 2
+for x = x+3 to 8
+    y = y & " " & x
+next
+Call ok(y = "for3: 5 6 7 8", "y = " & y)
+
+y = "for4:"
+for x = 5 to 4
+    y = y & " " & x
+next
+Call ok(y = "for4:", "y = " & y)
+
+y = "for5:"
+for x = 5 to 3 step true
+    y = y & " " & x
+next
+Call ok(y = "for5: 5 4 3", "y = " & y)
+
+y = "for6:"
+z = 4
+for x = 5 to z step 3-4
+    y = y & " " & x
+    z = 0
+next
+Call ok(y = "for6: 5 4", "y = " & y)
+
+y = "for7:"
+z = 1
+for x = 5 to 8 step z
+    y = y & " " & x
+    z = 2
+next
+Call ok(y = "for7: 5 6 7 8", "y = " & y)
+
+y = "for8:"
+for x = 5 to 8
+    y = y & " " & x
+    x = x+1
+next
+Call ok(y = "for8: 5 7", "y = " & y)
+
+for x = 1.5 to 1
+    Call ok(false, "for..to called when unexpected")
+next
+
+for x = 1 to 100
+    exit for
+    Call ok(false, "exit for not escaped the loop?")
+next
+
+do while true
+    for x = 1 to 100
+        exit do
+    next
+loop
+
+if null then call ok(false, "if null evaluated")
+
+while null
+    call ok(false, "while null evaluated")
+wend
+
+Call collectionObj.reset()
+y = 0
+x = 10
+for each x in collectionObj
+    y = y+1
+    Call ok(x = y, "x <> y")
+next
+Call ok(y = 3, "y = " & y)
+Call ok(getVT(x) = "VT_EMPTY*", "getVT(x) = " & getVT(x))
+
+Call collectionObj.reset()
+y = false
+for each x in collectionObj
+    if x = 2 then exit for
+    y = 1
+next
+Call ok(y = 1, "y = " & y)
+Call ok(x = 2, "x = " & x)
+
+x = false
+select case 3
+    case 2
+        Call ok(false, "unexpected case")
+    case 2
+        Call ok(false, "unexpected case")
+    case 4
+        Call ok(false, "unexpected case")
+    case "test"
+    case "another case"
+        Call ok(false, "unexpected case")
+    case 0, false, 2+1, 10
+        x = true
+    case ok(false, "unexpected case")
+        Call ok(false, "unexpected case")
+    case else
+        Call ok(false, "unexpected case")
+end select
+Call ok(x, "wrong case")
+
+x = false
+select case 3
+    case 3
+        x = true
+end select
+Call ok(x, "wrong case")
+
+x = false
+select case 2+2
+    case 3
+        Call ok(false, "unexpected case")
+    case else
+        x = true
+end select
+Call ok(x, "wrong case")
+
+y = "3"
+x = false
+select case y
+    case "3"
+        x = true
+    case 3
+        Call ok(false, "unexpected case")
+end select
+Call ok(x, "wrong case")
+
+select case 0
+    case 1
+        Call ok(false, "unexpected case")
+    case "2"
+        Call ok(false, "unexpected case")
+end select
+
+select case 0
+end select
+
+if false then
+Sub testsub
+    x = true
+End Sub
+end if
+
+x = false
+Call testsub
+Call ok(x, "x is false, testsub not called?")
+
+Sub SubSetTrue(v)
+    Call ok(not v, "v is not true")
+    v = true
+End Sub
+
+x = false
+SubSetTrue x
+Call ok(x, "x was not set by SubSetTrue")
+
+SubSetTrue false
+Call ok(not false, "false is no longer false?")
+
+Sub SubSetTrue2(ByRef v)
+    Call ok(not v, "v is not true")
+    v = true
+End Sub
+
+x = false
+SubSetTrue2 x
+Call ok(x, "x was not set by SubSetTrue")
+
+Sub TestSubArgVal(ByVal v)
+    Call ok(not v, "v is not false")
+    v = true
+    Call ok(v, "v is not true?")
+End Sub
+
+x = false
+Call TestSubArgVal(x)
+Call ok(not x, "x is true after TestSubArgVal call?")
+
+Sub TestSubMultiArgs(a,b,c,d,e)
+    Call ok(a=1, "a = " & a)
+    Call ok(b=2, "b = " & b)
+    Call ok(c=3, "c = " & c)
+    Call ok(d=4, "d = " & d)
+    Call ok(e=5, "e = " & e)
+End Sub
+
+Sub TestSubExit(ByRef a)
+    If a Then
+        Exit Sub
+    End If
+    Call ok(false, "Exit Sub not called?")
+End Sub
+
+Call TestSubExit(true)
+
+Sub TestSubExit2
+    for x = 1 to 100
+        Exit Sub
+    next
+End Sub
+Call TestSubExit2
+
+TestSubMultiArgs 1, 2, 3, 4, 5
+Call TestSubMultiArgs(1, 2, 3, 4, 5)
+
+Sub TestSubLocalVal
+    x = false
+    Call ok(not x, "local x is not false?")
+    Dim x
+    Dim a,b, c
+End Sub
+
+x = true
+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
+End Function
+end if
+
+x = false
+Call TestFunc
+Call ok(x, "x is false, testfunc not called?")
+
+Function FuncSetTrue(v)
+    Call ok(not v, "v is not true")
+    v = true
+End Function
+
+x = false
+FuncSetTrue x
+Call ok(x, "x was not set by FuncSetTrue")
+
+FuncSetTrue false
+Call ok(not false, "false is no longer false?")
+
+Function FuncSetTrue2(ByRef v)
+    Call ok(not v, "v is not true")
+    v = true
+End Function
+
+x = false
+FuncSetTrue2 x
+Call ok(x, "x was not set by FuncSetTrue")
+
+Function TestFuncArgVal(ByVal v)
+    Call ok(not v, "v is not false")
+    v = true
+    Call ok(v, "v is not true?")
+End Function
+
+x = false
+Call TestFuncArgVal(x)
+Call ok(not x, "x is true after TestFuncArgVal call?")
+
+Function TestFuncMultiArgs(a,b,c,d,e)
+    Call ok(a=1, "a = " & a)
+    Call ok(b=2, "b = " & b)
+    Call ok(c=3, "c = " & c)
+    Call ok(d=4, "d = " & d)
+    Call ok(e=5, "e = " & e)
+End Function
+
+TestFuncMultiArgs 1, 2, 3, 4, 5
+Call TestFuncMultiArgs(1, 2, 3, 4, 5)
+
+Function TestFuncLocalVal
+    x = false
+    Call ok(not x, "local x is not false?")
+    Dim x
+End Function
+
+x = true
+y = true
+Call TestFuncLocalVal
+Call ok(x, "global x is not true?")
+
+Function TestFuncExit(ByRef a)
+    If a Then
+        Exit Function
+    End If
+    Call ok(false, "Exit Function not called?")
+End Function
+
+Call TestFuncExit(true)
+
+Function TestFuncExit2(ByRef a)
+    For x = 1 to 100
+        For y = 1 to 100
+            Exit Function
+        Next
+    Next
+    Call ok(false, "Exit Function not called?")
+End Function
+
+Call TestFuncExit2(true)
+
+Sub SubParseTest
+End Sub : x = false
+Call SubParseTest
+
+Function FuncParseTest
+End Function : x = false
+
+Function ReturnTrue
+     ReturnTrue = false
+     ReturnTrue = true
+End Function
+
+Call ok(ReturnTrue(), "ReturnTrue returned false?")
+
+Function SetVal(ByRef x, ByVal v)
+    x = v
+    SetVal = x
+    Exit Function
+End Function
+
+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
+
+' Stop has an effect only in debugging mode
+Stop
+
+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
+
+Set x = obj
+Call ok(getVT(x) = "VT_DISPATCH*", "getVT(x) = " & getVT(x))
+
+Class TestClass
+    Public publicProp
+
+    Private privateProp
+
+    Public Function publicFunction()
+        privateSub()
+        publicFunction = 4
+    End Function
+
+    Public Property Get gsProp()
+        gsProp = privateProp
+        funcCalled = "gsProp get"
+        exit property
+        Call ok(false, "exit property not returned?")
+    End Property
+
+    Public Default Property Get DefValGet
+        DefValGet = privateProp
+        funcCalled = "GetDefVal"
+    End Property
+
+    Public Property Let DefValGet(x)
+    End Property
+
+    Public publicProp2
+
+    Public Sub publicSub
+    End Sub
+
+    Public Property Let gsProp(val)
+        privateProp = val
+        funcCalled = "gsProp let"
+        exit property
+        Call ok(false, "exit property not returned?")
+    End Property
+
+    Public Property Set gsProp(val)
+        funcCalled = "gsProp set"
+        exit property
+        Call ok(false, "exit property not returned?")
+    End Property
+
+    Public Sub setPrivateProp(x)
+        privateProp = x
+    End Sub
+
+    Function getPrivateProp
+        getPrivateProp = privateProp
+    End Function
+
+    Private Sub privateSub
+    End Sub
+
+    Public Sub Class_Initialize
+        publicProp2 = 2
+        privateProp = true
+    End Sub
+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())
+
+obj.publicSub()
+Call obj.publicSub
+Call obj.publicFunction()
+
+Call ok(getVT(obj.publicProp) = "VT_EMPTY", "getVT(obj.publicProp) = " & getVT(obj.publicProp))
+obj.publicProp = 3
+Call ok(obj.publicProp = 3, "obj.publicProp = " & obj.publicProp)
+obj.publicProp() = 3
+
+Call ok(obj.getPrivateProp() = true, "obj.getPrivateProp() = " & obj.getPrivateProp())
+Call obj.setPrivateProp(6)
+Call ok(obj.getPrivateProp = 6, "obj.getPrivateProp = " & obj.getPrivateProp)
+
+Dim funcCalled
+funcCalled = ""
+Call ok(obj.gsProp = 6, "obj.gsProp = " & obj.gsProp)
+Call ok(funcCalled = "gsProp get", "funcCalled = " & funcCalled)
+obj.gsProp = 3
+Call ok(funcCalled = "gsProp let", "funcCalled = " & funcCalled)
+Call ok(obj.getPrivateProp = 3, "obj.getPrivateProp = " & obj.getPrivateProp)
+Set obj.gsProp = New testclass
+Call ok(funcCalled = "gsProp set", "funcCalled = " & funcCalled)
+
+x = obj
+Call ok(x = 3, "(x = obj) = " & x)
+Call ok(funcCalled = "GetDefVal", "funcCalled = " & funcCalled)
+funcCalled = ""
+Call ok(obj = 3, "(x = obj) = " & obj)
+Call ok(funcCalled = "GetDefVal", "funcCalled = " & funcCalled)
+
+Call obj.Class_Initialize
+Call ok(obj.getPrivateProp() = true, "obj.getPrivateProp() = " & obj.getPrivateProp())
+
+x = (New testclass).publicProp
+
+Class TermTest
+    Public Sub Class_Terminate()
+        funcCalled = "terminate"
+    End Sub
+End Class
+
+Set obj = New TermTest
+funcCalled = ""
+Set obj = Nothing
+Call ok(funcCalled = "terminate", "funcCalled = " & funcCalled)
+
+Set obj = New TermTest
+funcCalled = ""
+Call obj.Class_Terminate
+Call ok(funcCalled = "terminate", "funcCalled = " & funcCalled)
+funcCalled = ""
+Set obj = Nothing
+Call ok(funcCalled = "terminate", "funcCalled = " & funcCalled)
+
+Call (New testclass).publicSub()
+Call (New testclass).publicSub
+
+x = "following ':' is correct syntax" :
+x = "following ':' is correct syntax" :: :
+:: x = "also correct syntax"
+rem another ugly way for comments
+x = "rem as simplestatement" : rem rem comment
+:
+
+Set obj = new EmptyClass
+Set x = obj
+Set y = new EmptyClass
+
+Call ok(obj is x, "obj is not x")
+Call ok(x is obj, "x is not obj")
+Call ok(not (obj is y), "obj is not y")
+Call ok(not obj is y, "obj is not y")
+Call ok(not (x is Nothing), "x is 1")
+Call ok(Nothing is Nothing, "Nothing is not Nothing")
+Call ok(x is obj and true, "x is obj and true is false")
+
+Class TestMe
+    Public Sub Test(MyMe)
+        Call ok(Me is MyMe, "Me is not MyMe")
+    End Sub
+End Class
+
+Set obj = New TestMe
+Call obj.test(obj)
+
+Call ok(getVT(test) = "VT_DISPATCH", "getVT(test) = " & getVT(test))
+Call ok(Me is Test, "Me is not Test")
+
+Const c1 = 1, c2 = 2, c3 = -3
+Call ok(c1 = 1, "c1 = " & c1)
+Call ok(getVT(c1) = "VT_I2", "getVT(c1) = " & getVT(c1))
+Call ok(c3 = -3, "c3 = " & c3)
+Call ok(getVT(c3) = "VT_I2", "getVT(c3) = " & getVT(c3))
+
+Const cb = True, cs = "test", cnull = null
+Call ok(cb, "cb = " & cb)
+Call ok(getVT(cb) = "VT_BOOL", "getVT(cb) = " & getVT(cb))
+Call ok(cs = "test", "cs = " & cs)
+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))
+
+if false then Const conststr = "str"
+Call ok(conststr = "str", "conststr = " & conststr)
+Call ok(getVT(conststr) = "VT_BSTR", "getVT(conststr) = " & getVT(conststr))
+Call ok(conststr = "str", "conststr = " & conststr)
+
+Sub ConstTestSub
+    Const funcconst = 1
+    Call ok(c1 = 1, "c1 = " & c1)
+    Call ok(funcconst = 1, "funcconst = " & funcconst)
+End Sub
+
+Call ConstTestSub
+Dim funcconst
+
+' Property may be used as an identifier (although it's a keyword)
+Sub TestProperty
+    Dim Property
+    PROPERTY = true
+    Call ok(property, "property = " & property)
+
+    for property = 1 to 2
+    next
+End Sub
+
+Call TestProperty
+
+Class Property
+    Public Sub Property()
+    End Sub
+
+    Sub Test(byref property)
+    End Sub
+End Class
+
+Class Property2
+    Function Property()
+    End Function
+
+
+    Sub Test(property)
+    End Sub
+
+    Sub Test2(byval property)
+    End Sub
+End Class
+
+reportSuccess()
diff --git a/rostests/winetests/vbscript/regexp.vbs b/rostests/winetests/vbscript/regexp.vbs
new file mode 100644 (file)
index 0000000..72fa108
--- /dev/null
@@ -0,0 +1,171 @@
+'
+' Copyright 2013 Piotr Caban for CodeWeavers
+'
+' This library is free software; you can redistribute it and/or
+' modify it under the terms of the GNU Lesser General Public
+' License as published by the Free Software Foundation; either
+' version 2.1 of the License, or (at your option) any later version.
+'
+' This library is distributed in the hope that it will be useful,
+' but WITHOUT ANY WARRANTY; without even the implied warranty of
+' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+' Lesser General Public License for more details.
+'
+' You should have received a copy of the GNU Lesser General Public
+' License along with this library; if not, write to the Free Software
+' Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+'
+
+Option Explicit
+
+Dim x, matches, match, submatch
+
+Set x = CreateObject("vbscript.regexp")
+Call ok(getVT(x.Pattern) = "VT_BSTR", "getVT(RegExp.Pattern) = " & getVT(x.Pattern))
+Call ok(x.Pattern = "", "RegExp.Pattern = " & x.Pattern)
+Call ok(getVT(x.IgnoreCase) = "VT_BOOL", "getVT(RegExp.IgnoreCase) = " & getVT(x.IgnoreCase))
+Call ok(x.IgnoreCase = false, "RegExp.IgnoreCase = " & x.IgnoreCase)
+Call ok(getVT(x.Global) = "VT_BOOL", "getVT(RegExp.Global) = " & getVT(x.Global))
+Call ok(x.Global = false, "RegExp.Global = " & x.Global)
+Call ok(getVT(x.Multiline) = "VT_BOOL", "getVT(RegExp.Multiline) = " & getVT(x.Multiline))
+Call ok(x.Multiline = false, "RegExp.Multiline = " & x.Multiline)
+
+x.Pattern = "a+"
+matches = x.Test(" aabaaa")
+Call ok(matches = true, "RegExp.Test returned: " & matches)
+Set matches = x.Execute(" aabaaa")
+Call ok(getVT(matches.Count) = "VT_I4", "getVT(matches.Count) = " & getVT(matches.Count))
+Call ok(matches.Count = 1, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "aa", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 1, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 2, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+
+x.Global = true
+Set matches = x.Execute(" aabaaa")
+Call ok(matches.Count = 2, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "aa", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 1, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 2, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+Set match = matches.Item(1)
+Call ok(match.Value = "aaa", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 4, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 3, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+
+Set matches = x.Execute(" aabaaa")
+Call ok(matches.Count = 2, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "aa", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 1, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 2, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+
+x.Pattern = "^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$"
+x.Global = false
+Set matches = x.Execute("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
+Call ok(matches.Count = 0, "matches.Count = " & matches.Count)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+
+x.Pattern = "(a|b)+|(c)"
+Set matches = x.Execute("aa")
+Call ok(matches.Count = 1, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "aa", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 0, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 2, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 2, "submatch.Count = " & submatch.Count)
+Call ok(getVT(submatch.Item(0)) = "VT_BSTR", "getVT(submatch.Item(0)) = " & getVT(submatch.Item(0)))
+Call ok(submatch.Item(0) = "a", "submatch.Item(0) = " & submatch.Item(0))
+Call ok(getVT(submatch.Item(1)) = "VT_EMPTY", "getVT(submatch.Item(1)) = " & getVT(submatch.Item(1)))
+Call ok(submatch.Item(1) = "", "submatch.Item(0) = " & submatch.Item(1))
+
+matches = x.Test("  a ")
+Call ok(matches = true, "RegExp.Test returned: " & matches)
+matches = x.Test("  a ")
+Call ok(matches = true, "RegExp.Test returned: " & matches)
+
+x.Pattern = "\[([^\[]+)\]"
+x.Global = true
+Set matches = x.Execute(" [test]  ")
+Call ok(matches.Count = 1, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "[test]", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 1, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 6, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 1, "submatch.Count = " & submatch.Count)
+Call ok(submatch.Item(0) = "test", "submatch.Item(0) = " & submatch.Item(0))
+
+x.Pattern = "Ab"
+x.IgnoreCase = true
+Set matches = x.Execute("abcaBc")
+Call ok(matches.Count = 2, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "ab", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 0, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 2, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+Set match = matches.Item(1)
+Call ok(match.Value = "aB", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 3, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 2, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+
+x.Pattern = "a+b"
+x.IgnoreCase = false
+Set matches = x.Execute("aaabcabc")
+Call ok(matches.Count = 2, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "aaab", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 0, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 4, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+Set match = matches.Item(1)
+Call ok(match.Value = "ab", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 5, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 2, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+
+x.Pattern = "\\"
+Set matches = x.Execute("aaa\\cabc")
+Call ok(matches.Count = 2, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "\", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 3, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 1, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+Set match = matches.Item(1)
+Call ok(match.Value = "\", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 4, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 1, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 0, "submatch.Count = " & submatch.Count)
+
+x.Pattern = "(a)(b)cabc"
+Set matches = x.Execute("abcabc")
+Call ok(matches.Count = 1, "matches.Count = " & matches.Count)
+Set match = matches.Item(0)
+Call ok(match.Value = "abcabc", "match.Value = " & match.Value)
+Call ok(match.FirstIndex = 0, "match.FirstIndex = " & match.FirstIndex)
+Call ok(match.Length = 6, "match.Length = " & match.Length)
+Set submatch = match.SubMatches
+Call ok(submatch.Count = 2, "submatch.Count = " & submatch.Count)
+Call ok(submatch.Item(0) = "a", "submatch.Item(0) = " & submatch.Item(0))
+Call ok(submatch.Item(1) = "b", "submatch.Item(0) = " & submatch.Item(1))
+
+Call reportSuccess()
diff --git a/rostests/winetests/vbscript/rsrc.rc b/rostests/winetests/vbscript/rsrc.rc
new file mode 100644 (file)
index 0000000..1fb3440
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2011 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* @makedep: api.vbs */
+api.vbs 40 "api.vbs"
+
+/* @makedep: lang.vbs */
+lang.vbs 40 "lang.vbs"
+
+/* @makedep: regexp.vbs */
+regexp.vbs 40 "regexp.vbs"
diff --git a/rostests/winetests/vbscript/run.c b/rostests/winetests/vbscript/run.c
new file mode 100644 (file)
index 0000000..e471b44
--- /dev/null
@@ -0,0 +1,1985 @@
+/*
+ * Copyright 2011 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+
+#define COBJMACROS
+#define CONST_VTABLE
+
+#include <windef.h>
+#include <winbase.h>
+#include <winnls.h>
+#include <ole2.h>
+#include <dispex.h>
+#include <activscp.h>
+
+#include <vbsregexp55.h>
+
+#include <wine/test.h>
+
+#ifdef _WIN64
+
+#define IActiveScriptParse_QueryInterface IActiveScriptParse64_QueryInterface
+#define IActiveScriptParse_Release IActiveScriptParse64_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
+#define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_64_Release
+#define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_64_ParseProcedureText
+
+#else
+
+#define IActiveScriptParse_QueryInterface IActiveScriptParse32_QueryInterface
+#define IActiveScriptParse_Release IActiveScriptParse32_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
+#define IActiveScriptParseProcedure2_Release IActiveScriptParseProcedure2_32_Release
+#define IActiveScriptParseProcedure2_ParseProcedureText IActiveScriptParseProcedure2_32_ParseProcedureText
+
+#endif
+
+extern const CLSID CLSID_VBScript;
+extern const CLSID CLSID_VBScriptRegExp;
+
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+    expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_EXPECT(func) \
+    do { \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+#define CLEAR_CALLED(func) \
+    expect_ ## func = called_ ## func = FALSE
+
+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);
+DEFINE_EXPECT(global_propargput_d);
+DEFINE_EXPECT(global_propargput_i);
+DEFINE_EXPECT(global_propargput1_d);
+DEFINE_EXPECT(global_propargput1_i);
+DEFINE_EXPECT(collectionobj_newenum_i);
+DEFINE_EXPECT(Next);
+DEFINE_EXPECT(GetWindow);
+DEFINE_EXPECT(GetUIBehavior);
+DEFINE_EXPECT(EnableModeless);
+
+#define DISPID_GLOBAL_REPORTSUCCESS 1000
+#define DISPID_GLOBAL_TRACE         1001
+#define DISPID_GLOBAL_OK            1002
+#define DISPID_GLOBAL_GETVT         1003
+#define DISPID_GLOBAL_ISENGLANG     1004
+#define DISPID_GLOBAL_VBVAR         1005
+#define DISPID_GLOBAL_TESTOBJ       1006
+#define DISPID_GLOBAL_ISNULLDISP    1007
+#define DISPID_GLOBAL_TESTDISP      1008
+#define DISPID_GLOBAL_REFOBJ        1009
+#define DISPID_GLOBAL_COUNTER       1010
+#define DISPID_GLOBAL_PROPARGPUT    1011
+#define DISPID_GLOBAL_PROPARGPUT1   1012
+#define DISPID_GLOBAL_COLLOBJ       1013
+#define DISPID_GLOBAL_DOUBLEASSTRING 1014
+
+#define DISPID_TESTOBJ_PROPGET      2000
+#define DISPID_TESTOBJ_PROPPUT      2001
+
+#define DISPID_COLLOBJ_RESET        3000
+
+static const WCHAR testW[] = {'t','e','s','t',0};
+static const WCHAR emptyW[] = {0};
+
+static BOOL strict_dispid_check, is_english, allow_ui;
+static const char *test_name = "(null)";
+static int test_counter;
+static SCRIPTUICHANDLING uic_handling = SCRIPTUICHANDLING_NOUIERROR;
+
+static BSTR a2bstr(const char *str)
+{
+    BSTR ret;
+    int len;
+
+    len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+    ret = SysAllocStringLen(NULL, len-1);
+    MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
+
+    return ret;
+}
+
+static int strcmp_wa(LPCWSTR strw, const char *stra)
+{
+    CHAR buf[512];
+    WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), 0, 0);
+    return lstrcmpA(buf, stra);
+}
+
+static const char *debugstr_guid(REFIID riid)
+{
+    static char buf[50];
+
+    sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+            riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
+            riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
+            riid->Data4[5], riid->Data4[6], riid->Data4[7]);
+
+    return buf;
+}
+
+static const char *vt2a(VARIANT *v)
+{
+    if(V_VT(v) == (VT_BYREF|VT_VARIANT)) {
+        static char buf[64];
+        sprintf(buf, "%s*", vt2a(V_BYREF(v)));
+        return buf;
+    }
+
+    switch(V_VT(v)) {
+    case VT_EMPTY:
+        return "VT_EMPTY";
+    case VT_NULL:
+        return "VT_NULL";
+    case VT_I2:
+        return "VT_I2";
+    case VT_I4:
+        return "VT_I4";
+    case VT_R8:
+        return "VT_R8";
+    case VT_DATE:
+        return "VT_DATE";
+    case VT_BSTR:
+        return "VT_BSTR";
+    case VT_DISPATCH:
+        return "VT_DISPATCH";
+    case VT_BOOL:
+        return "VT_BOOL";
+    case VT_ARRAY|VT_VARIANT:
+        return "VT_ARRAY|VT_VARIANT";
+    default:
+        ok(0, "unknown vt %d\n", V_VT(v));
+        return NULL;
+    }
+}
+
+/* Returns true if the user interface is in English. Note that this does not
+ * presume of the formatting of dates, numbers, etc.
+ */
+static BOOL is_lang_english(void)
+{
+    static HMODULE hkernel32 = NULL;
+    static LANGID (WINAPI *pGetThreadUILanguage)(void) = NULL;
+    static LANGID (WINAPI *pGetUserDefaultUILanguage)(void) = NULL;
+
+    if (!hkernel32)
+    {
+        hkernel32 = GetModuleHandleA("kernel32.dll");
+        pGetThreadUILanguage = (void*)GetProcAddress(hkernel32, "GetThreadUILanguage");
+        pGetUserDefaultUILanguage = (void*)GetProcAddress(hkernel32, "GetUserDefaultUILanguage");
+    }
+    if (pGetThreadUILanguage && PRIMARYLANGID(pGetThreadUILanguage()) != LANG_ENGLISH)
+        return FALSE;
+    if (pGetUserDefaultUILanguage && PRIMARYLANGID(pGetUserDefaultUILanguage()) != LANG_ENGLISH)
+        return FALSE;
+
+    return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
+}
+
+static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
+{
+    ok(0, "unexpected call\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService,
+        REFIID riid, void **ppv)
+{
+    ok(0, "unexpected service %s\n", debugstr_guid(guidService));
+    return E_NOINTERFACE;
+}
+
+static const IServiceProviderVtbl ServiceProviderVtbl = {
+    ServiceProvider_QueryInterface,
+    ServiceProvider_AddRef,
+    ServiceProvider_Release,
+    ServiceProvider_QueryService
+};
+
+static IServiceProvider caller_sp = { &ServiceProviderVtbl };
+
+static void test_disp(IDispatch *disp)
+{
+    DISPID id, public_prop_id, public_prop2_id, public_func_id, public_sub_id, defvalget_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;
+
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres);
+
+    str = a2bstr("publicProp");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &public_prop_id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(publicProp) failed: %08x\n", hres);
+
+    str = a2bstr("PUBLICPROP");
+    hres = IDispatchEx_GetDispID(dispex, str, 0, &id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(PUBLICPROP) failed: %08x\n", hres);
+    ok(public_prop_id == id, "id = %d\n", public_prop_id);
+
+    str = a2bstr("publicPROP2");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &public_prop2_id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(publicProp2) failed: %08x\n", hres);
+
+    str = a2bstr("defValGet");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &defvalget_id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(defValGet) failed: %08x\n", hres);
+    ok(defvalget_id == DISPID_VALUE, "id = %d\n", defvalget_id);
+
+    str = a2bstr("privateProp");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &id);
+    SysFreeString(str);
+    ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(privateProp) failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
+    ok(id == -1, "id = %d\n", id);
+
+    str = a2bstr("class_initialize");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseInsensitive, &id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(publicProp2) failed: %08x\n", hres);
+
+    hres = IDispatchEx_InvokeEx(dispex, public_prop_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));
+
+    V_VT(args) = VT_BOOL;
+    V_BOOL(args) = VARIANT_TRUE;
+    dp.cArgs = dp.cNamedArgs = 1;
+    V_VT(&v) = VT_BOOL;
+    hres = IDispatchEx_InvokeEx(dispex, public_prop_id, 0, DISPATCH_PROPERTYPUT, &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_prop_id, 0, DISPATCH_PROPERTYGET|DISPATCH_METHOD, &dp, &v, &ei, NULL);
+    ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    ok(V_VT(&v) == VT_BOOL, "V_VT(v) = %d\n", V_VT(&v));
+    ok(V_BOOL(&v), "V_BOOL(v) = %x\n", V_BOOL(&v));
+
+    dp.cArgs = dp.cNamedArgs = 0;
+    hres = IDispatchEx_InvokeEx(dispex, public_prop_id, 0, DISPATCH_PROPERTYGET, &dp, &v, &ei, NULL);
+    ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
+    ok(V_VT(&v) == VT_BOOL, "V_VT(v) = %d\n", V_VT(&v));
+    ok(V_BOOL(&v), "V_BOOL(v) = %x\n", V_BOOL(&v));
+
+    dp.cArgs = 1;
+    hres = IDispatchEx_InvokeEx(dispex, public_prop_id, 0, DISPATCH_PROPERTYGET|DISPATCH_METHOD, &dp, &v, &ei, NULL);
+    ok(hres == DISP_E_MEMBERNOTFOUND, "InvokeEx failed: %08x, expected DISP_E_MEMBERNOTFOUND\n", hres);
+    ok(V_VT(&v) == VT_EMPTY, "V_VT(v) = %d\n", V_VT(&v));
+
+    V_VT(args) = VT_BOOL;
+    V_BOOL(args) = VARIANT_FALSE;
+    dp.cArgs = 1;
+    V_VT(&v) = VT_BOOL;
+    hres = IDispatchEx_InvokeEx(dispex, public_prop_id, 0, DISPATCH_PROPERTYPUT, &dp, NULL, &ei, NULL);
+    ok(hres == DISP_E_PARAMNOTOPTIONAL, "InvokeEx failed: %08x, expected DISP_E_PARAMNOTOPTIONAL\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");
+
+    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_PROPERTYGET, &dp, &v, &ei, NULL);
+    ok(hres == DISP_E_MEMBERNOTFOUND, "InvokeEx failed: %08x, expected DISP_E_MEMBERNOTFOUND\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_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_PROPERTYGET, &dp, &v, &ei, NULL);
+    ok(hres == DISP_E_MEMBERNOTFOUND, "InvokeEx failed: %08x, expected DISP_E_MEMBERNOTFOUND\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));
+
+    V_VT(args) = VT_BOOL;
+    V_BOOL(args) = VARIANT_TRUE;
+    dp.cArgs = dp.cNamedArgs = 1;
+    hres = IDispatchEx_InvokeEx(dispex, public_sub_id, 0, DISPATCH_PROPERTYPUT, &dp, NULL, &ei, NULL);
+    ok(FAILED(hres), "InvokeEx succeeded: %08x\n", hres);
+
+    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);
+    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);
+
+    str = a2bstr("publicProp");
+    hres = IDispatchEx_GetDispID(dispex, str, 0x80000000|fdexNameCaseInsensitive, &public_prop_id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(publicProp) failed: %08x\n", hres);
+
+    id = 0xdeadbeef;
+    str = a2bstr("publicProp");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(publicProp) failed: %08x\n", hres);
+    ok(id == public_prop_id, "id = %d, expected %d\n", id, public_prop_id);
+
+    id = 0xdeadbeef;
+    str = a2bstr("publicprop");
+    hres = IDispatchEx_GetDispID(dispex, str, fdexNameCaseSensitive, &id);
+    SysFreeString(str);
+    ok(hres == S_OK, "GetDispID(publicProp) failed: %08x\n", hres);
+    ok(id == public_prop_id, "id = %d, expected %d\n", id, public_prop_id);
+
+    IDispatchEx_Release(dispex);
+}
+
+#define test_grfdex(a,b) _test_grfdex(__LINE__,a,b)
+static void _test_grfdex(unsigned line, DWORD grfdex, DWORD expect)
+{
+    ok_(__FILE__,line)(grfdex == expect, "grfdex = %x, expected %x\n", grfdex, expect);
+}
+
+static IDispatchEx enumDisp;
+
+static HRESULT WINAPI EnumVARIANT_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT)) {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    if(IsEqualGUID(riid, &IID_IDispatch)) {
+        *ppv = &enumDisp;
+        return S_OK;
+    }
+
+    ok(0, "unexpected call %s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI EnumVARIANT_AddRef(IEnumVARIANT *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI EnumVARIANT_Release(IEnumVARIANT *iface)
+{
+    return 1;
+}
+
+static unsigned next_cnt;
+
+static HRESULT WINAPI EnumVARIANT_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
+{
+    if(strict_dispid_check)
+        CHECK_EXPECT2(Next);
+
+    ok(celt == 1, "celt = %d\n", celt);
+    ok(V_VT(rgVar) == VT_EMPTY, "V_VT(rgVar) = %d\n", V_VT(rgVar));
+    ok(!pCeltFetched, "pCeltFetched = %p\n", pCeltFetched);
+
+    if(next_cnt++ < 3) {
+        V_VT(rgVar) = VT_I2;
+        V_I2(rgVar) = next_cnt;
+        return S_OK;
+    }
+
+    return S_FALSE;
+}
+
+static HRESULT WINAPI EnumVARIANT_Skip(IEnumVARIANT *iface, ULONG celt)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI EnumVARIANT_Reset(IEnumVARIANT *iface)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI EnumVARIANT_Clone(IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static const IEnumVARIANTVtbl EnumVARIANTVtbl = {
+    EnumVARIANT_QueryInterface,
+    EnumVARIANT_AddRef,
+    EnumVARIANT_Release,
+    EnumVARIANT_Next,
+    EnumVARIANT_Skip,
+    EnumVARIANT_Reset,
+    EnumVARIANT_Clone
+};
+
+static IEnumVARIANT enumObj = { &EnumVARIANTVtbl };
+
+static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(riid, &IID_IUnknown)
+       || IsEqualGUID(riid, &IID_IDispatch)
+       || IsEqualGUID(riid, &IID_IDispatchEx))
+        *ppv = iface;
+    else {
+        trace("QI %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
+                                              LCID lcid, ITypeInfo **ppTInfo)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
+                                                LPOLESTR *rgszNames, UINT cNames,
+                                                LCID lcid, DISPID *rgDispId)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
+                            REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+                            VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
+{
+    ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
+        VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+    ok(0, "unexpected call %d\n", id);
+    return E_NOTIMPL;
+}
+
+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;
+    }
+
+    ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName));
+    return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT WINAPI testObj_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
+        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);
+
+        ok(wFlags == DISPATCH_PROPERTYPUT, "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n");
+        ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
+        ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pdp->rgdispidNamedArgs[0] == DISPID_PROPERTYPUT, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]);
+        ok(!pvarRes, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        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;
+    }
+
+    ok(0, "unexpected call %d\n", id);
+    return E_FAIL;
+}
+
+static IDispatchExVtbl testObjVtbl = {
+    DispatchEx_QueryInterface,
+    DispatchEx_AddRef,
+    DispatchEx_Release,
+    DispatchEx_GetTypeInfoCount,
+    DispatchEx_GetTypeInfo,
+    DispatchEx_GetIDsOfNames,
+    DispatchEx_Invoke,
+    testObj_GetDispID,
+    testObj_InvokeEx,
+    DispatchEx_DeleteMemberByName,
+    DispatchEx_DeleteMemberByDispID,
+    DispatchEx_GetMemberProperties,
+    DispatchEx_GetMemberName,
+    DispatchEx_GetNextDispID,
+    DispatchEx_GetNameSpaceParent
+};
+
+static IDispatchEx testObj = { &testObjVtbl };
+
+static HRESULT WINAPI enumDisp_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
+{
+    return IEnumVARIANT_QueryInterface(&enumObj, riid, ppv);
+}
+
+static IDispatchExVtbl enumDispVtbl = {
+    enumDisp_QueryInterface,
+    DispatchEx_AddRef,
+    DispatchEx_Release,
+    DispatchEx_GetTypeInfoCount,
+    DispatchEx_GetTypeInfo,
+    DispatchEx_GetIDsOfNames,
+    DispatchEx_Invoke,
+    DispatchEx_GetDispID,
+    DispatchEx_InvokeEx,
+    DispatchEx_DeleteMemberByName,
+    DispatchEx_DeleteMemberByDispID,
+    DispatchEx_GetMemberProperties,
+    DispatchEx_GetMemberName,
+    DispatchEx_GetNextDispID,
+    DispatchEx_GetNameSpaceParent
+};
+
+static IDispatchEx enumDisp = { &enumDispVtbl };
+
+static HRESULT WINAPI collectionObj_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
+{
+    if(!strcmp_wa(bstrName, "reset")) {
+        *pid = DISPID_COLLOBJ_RESET;
+        return S_OK;
+    }
+
+    ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName));
+    return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT WINAPI collectionObj_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
+        VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+    switch(id) {
+    case DISPID_NEWENUM:
+        if(strict_dispid_check)
+            CHECK_EXPECT(collectionobj_newenum_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_UNKNOWN;
+        V_UNKNOWN(pvarRes) = (IUnknown*)&enumObj;
+        return S_OK;
+    case DISPID_COLLOBJ_RESET:
+        next_cnt = 0;
+        return S_OK;
+    }
+
+    ok(0, "unexpected call %d\n", id);
+    return E_NOTIMPL;
+}
+
+static IDispatchExVtbl collectionObjVtbl = {
+    DispatchEx_QueryInterface,
+    DispatchEx_AddRef,
+    DispatchEx_Release,
+    DispatchEx_GetTypeInfoCount,
+    DispatchEx_GetTypeInfo,
+    DispatchEx_GetIDsOfNames,
+    DispatchEx_Invoke,
+    collectionObj_GetDispID,
+    collectionObj_InvokeEx,
+    DispatchEx_DeleteMemberByName,
+    DispatchEx_DeleteMemberByDispID,
+    DispatchEx_GetMemberProperties,
+    DispatchEx_GetMemberName,
+    DispatchEx_GetNextDispID,
+    DispatchEx_GetNameSpaceParent
+};
+
+static IDispatchEx collectionObj = { &collectionObjVtbl };
+
+static ULONG refobj_ref;
+
+static ULONG WINAPI RefObj_AddRef(IDispatchEx *iface)
+{
+    return ++refobj_ref;
+}
+
+static ULONG WINAPI RefObj_Release(IDispatchEx *iface)
+{
+    return --refobj_ref;
+}
+
+static IDispatchExVtbl RefObjVtbl = {
+    DispatchEx_QueryInterface,
+    RefObj_AddRef,
+    RefObj_Release,
+    DispatchEx_GetTypeInfoCount,
+    DispatchEx_GetTypeInfo,
+    DispatchEx_GetIDsOfNames,
+    DispatchEx_Invoke,
+    DispatchEx_GetDispID,
+    DispatchEx_InvokeEx,
+    DispatchEx_DeleteMemberByName,
+    DispatchEx_DeleteMemberByDispID,
+    DispatchEx_GetMemberProperties,
+    DispatchEx_GetMemberName,
+    DispatchEx_GetNextDispID,
+    DispatchEx_GetNameSpaceParent
+};
+
+static IDispatchEx RefObj = { &RefObjVtbl };
+
+static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
+{
+    if(!strcmp_wa(bstrName, "ok")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_OK;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "trace")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_TRACE;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "reportSuccess")) {
+        CHECK_EXPECT(global_success_d);
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_REPORTSUCCESS;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "getVT")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_GETVT;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "isEnglishLang")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_ISENGLANG;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "testObj")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_TESTOBJ;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "collectionObj")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_COLLOBJ;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "vbvar")) {
+        CHECK_EXPECT(global_vbvar_d);
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_VBVAR;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "isNullDisp")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_ISNULLDISP;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "testDisp")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_TESTDISP;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "RefObj")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_REFOBJ;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "propargput")) {
+        CHECK_EXPECT(global_propargput_d);
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_PROPARGPUT;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "propargput1")) {
+        CHECK_EXPECT(global_propargput1_d);
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_PROPARGPUT1;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "counter")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_COUNTER;
+        return S_OK;
+    }
+    if(!strcmp_wa(bstrName, "doubleAsString")) {
+        test_grfdex(grfdex, fdexNameCaseInsensitive);
+        *pid = DISPID_GLOBAL_DOUBLEASSTRING;
+        return S_OK;
+    }
+
+    if(strict_dispid_check && strcmp_wa(bstrName, "x"))
+        ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
+    return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
+        VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
+{
+    switch(id) {
+    case DISPID_GLOBAL_OK: {
+        VARIANT *b;
+
+        ok(wFlags == INVOKE_FUNC || 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 == 2, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        if(wFlags & INVOKE_PROPERTYGET)
+            ok(pvarRes != NULL, "pvarRes == NULL\n");
+        else
+            ok(!pvarRes, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        ok(V_VT(pdp->rgvarg) == VT_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
+
+        b = pdp->rgvarg+1;
+        if(V_VT(b) == (VT_BYREF|VT_VARIANT))
+            b = V_BYREF(b);
+
+        ok(V_VT(b) == VT_BOOL, "V_VT(b) = %d\n", V_VT(b));
+
+        ok(V_BOOL(b), "%s: %s\n", test_name, wine_dbgstr_w(V_BSTR(pdp->rgvarg)));
+        return S_OK;
+    }
+
+     case DISPID_GLOBAL_TRACE:
+        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_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
+        if(V_VT(pdp->rgvarg) == VT_BSTR)
+            trace("%s: %s\n", test_name, wine_dbgstr_w(V_BSTR(pdp->rgvarg)));
+
+        return S_OK;
+
+    case DISPID_GLOBAL_REPORTSUCCESS:
+        CHECK_EXPECT(global_success_i);
+
+        ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
+        ok(pdp->cArgs == 0, "cArgs = %d\n", pdp->cArgs);
+        ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(!pvarRes, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        return S_OK;
+
+    case DISPID_GLOBAL_GETVT:
+        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(V_VT(pvarRes) ==  VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes));
+        ok(pei != NULL, "pei == NULL\n");
+
+        V_VT(pvarRes) = VT_BSTR;
+        V_BSTR(pvarRes) = a2bstr(vt2a(pdp->rgvarg));
+        return S_OK;
+
+    case DISPID_GLOBAL_ISENGLANG:
+        ok(wFlags == (INVOKE_FUNC|INVOKE_PROPERTYGET), "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
+        ok(pdp->cArgs == 0, "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_BOOL;
+        V_BOOL(pvarRes) = is_english ? VARIANT_TRUE : VARIANT_FALSE;
+        return S_OK;
+
+    case DISPID_GLOBAL_VBVAR:
+        CHECK_EXPECT(global_vbvar_i);
+
+        ok(wFlags == DISPATCH_PROPERTYPUT, "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n");
+        ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
+        ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pdp->rgdispidNamedArgs[0] == DISPID_PROPERTYPUT, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]);
+        ok(!pvarRes, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        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:
+        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_DISPATCH;
+        V_DISPATCH(pvarRes) = (IDispatch*)&testObj;
+        return S_OK;
+
+    case DISPID_GLOBAL_COLLOBJ:
+        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_DISPATCH;
+        V_DISPATCH(pvarRes) = (IDispatch*)&collectionObj;
+        return S_OK;
+
+    case DISPID_GLOBAL_REFOBJ:
+        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");
+
+        IDispatchEx_AddRef(&RefObj);
+        V_VT(pvarRes) = VT_DISPATCH;
+        V_DISPATCH(pvarRes) = (IDispatch*)&RefObj;
+        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;
+    }
+
+    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;
+
+    case DISPID_GLOBAL_PROPARGPUT:
+        CHECK_EXPECT(global_propargput_i);
+
+        ok(wFlags == DISPATCH_PROPERTYPUT, "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n");
+        ok(pdp->cArgs == 3, "cArgs = %d\n", pdp->cArgs);
+        ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pdp->rgdispidNamedArgs[0] == DISPID_PROPERTYPUT, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]);
+        ok(!pvarRes, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        ok(V_VT(pdp->rgvarg) == VT_I2, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
+        ok(V_I2(pdp->rgvarg) == 0, "V_I2(psp->rgvargs) = %d\n", V_I2(pdp->rgvarg));
+
+        ok(V_VT(pdp->rgvarg+1) == VT_I2, "V_VT(psp->rgvargs+1) = %d\n", V_VT(pdp->rgvarg+1));
+        ok(V_I2(pdp->rgvarg+1) == 2, "V_I2(psp->rgvargs+1) = %d\n", V_I2(pdp->rgvarg+1));
+
+        ok(V_VT(pdp->rgvarg+2) == VT_I2, "V_VT(psp->rgvargs+2) = %d\n", V_VT(pdp->rgvarg+2));
+        ok(V_I2(pdp->rgvarg+2) == 1, "V_I2(psp->rgvargs+2) = %d\n", V_I2(pdp->rgvarg+2));
+        return S_OK;
+
+    case DISPID_GLOBAL_PROPARGPUT1:
+        CHECK_EXPECT(global_propargput1_i);
+
+        ok(wFlags == DISPATCH_PROPERTYPUT, "wFlags = %x\n", wFlags);
+        ok(pdp != NULL, "pdp == NULL\n");
+        ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n");
+        ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs);
+        ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs);
+        ok(pdp->rgdispidNamedArgs[0] == DISPID_PROPERTYPUT, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]);
+        ok(!pvarRes, "pvarRes != NULL\n");
+        ok(pei != NULL, "pei == NULL\n");
+
+        ok(V_VT(pdp->rgvarg) == VT_I2, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
+        ok(V_I2(pdp->rgvarg) == 0, "V_I2(psp->rgvargs) = %d\n", V_I2(pdp->rgvarg));
+
+        ok(V_VT(pdp->rgvarg+1) == VT_I2, "V_VT(psp->rgvargs+1) = %d\n", V_VT(pdp->rgvarg+1));
+        ok(V_I2(pdp->rgvarg+1) == 1, "V_I2(psp->rgvargs+1) = %d\n", V_I2(pdp->rgvarg+1));
+
+        return S_OK;
+
+    case DISPID_GLOBAL_COUNTER:
+        ok(pdp != NULL, "pdp == NULL\n");
+        todo_wine ok(pdp->rgvarg != NULL, "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(V_VT(pvarRes) ==  VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes));
+        ok(pei != NULL, "pei == NULL\n");
+
+        V_VT(pvarRes) = VT_I2;
+        V_I2(pvarRes) = test_counter++;
+        return S_OK;
+
+    case DISPID_GLOBAL_DOUBLEASSTRING:
+        ok(wFlags == (INVOKE_FUNC|INVOKE_PROPERTYGET), "wFlags = %x\n", wFlags);
+        ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
+        ok(V_VT(pdp->rgvarg) == VT_R8, "V_VT(pdp->rgvarg) = %d\n", V_VT(pdp->rgvarg));
+        ok(pvarRes != NULL, "pvarRes == NULL\n");
+
+        V_VT(pvarRes) = VT_BSTR;
+        return VarBstrFromR8(V_R8(pdp->rgvarg), 0, 0, &V_BSTR(pvarRes));
+    }
+
+    ok(0, "unexpected call %d\n", id);
+    return DISP_E_MEMBERNOTFOUND;
+}
+
+static IDispatchExVtbl GlobalVtbl = {
+    DispatchEx_QueryInterface,
+    DispatchEx_AddRef,
+    DispatchEx_Release,
+    DispatchEx_GetTypeInfoCount,
+    DispatchEx_GetTypeInfo,
+    DispatchEx_GetIDsOfNames,
+    DispatchEx_Invoke,
+    Global_GetDispID,
+    Global_InvokeEx,
+    DispatchEx_DeleteMemberByName,
+    DispatchEx_DeleteMemberByDispID,
+    DispatchEx_GetMemberProperties,
+    DispatchEx_GetMemberName,
+    DispatchEx_GetNextDispID,
+    DispatchEx_GetNameSpaceParent
+};
+
+static IDispatchEx Global = { &GlobalVtbl };
+
+static HRESULT WINAPI ActiveScriptSiteWindow_QueryInterface(IActiveScriptSiteWindow *iface, REFIID riid, void **ppv)
+{
+    ok(0, "unexpected call\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ActiveScriptSiteWindow_AddRef(IActiveScriptSiteWindow *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ActiveScriptSiteWindow_Release(IActiveScriptSiteWindow *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow *iface, HWND *phwnd)
+{
+    if(!allow_ui)
+        CHECK_EXPECT(GetWindow);
+    *phwnd = NULL;
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptSiteWindow_EnableModeless(IActiveScriptSiteWindow *iface, BOOL fEnable)
+{
+    if(allow_ui)
+        return S_OK;
+
+    CHECK_EXPECT(EnableModeless);
+    ok(!fEnable, "fEnable = %x\n", fEnable);
+    return E_FAIL;
+}
+
+static const IActiveScriptSiteWindowVtbl ActiveScriptSiteWindowVtbl = {
+    ActiveScriptSiteWindow_QueryInterface,
+    ActiveScriptSiteWindow_AddRef,
+    ActiveScriptSiteWindow_Release,
+    ActiveScriptSiteWindow_GetWindow,
+    ActiveScriptSiteWindow_EnableModeless
+};
+
+static IActiveScriptSiteWindow ActiveScriptSiteWindow = { &ActiveScriptSiteWindowVtbl };
+
+static HRESULT WINAPI ActiveScriptSiteUIControl_QueryInterface(IActiveScriptSiteUIControl *iface, REFIID riid, void **ppv)
+{
+    ok(0, "unexpected call\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ActiveScriptSiteUIControl_AddRef(IActiveScriptSiteUIControl *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ActiveScriptSiteUIControl_Release(IActiveScriptSiteUIControl *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ActiveScriptSiteUIControl_GetUIBehavior(IActiveScriptSiteUIControl *iface, SCRIPTUICITEM UicItem,
+        SCRIPTUICHANDLING *pUicHandling)
+{
+    if(!allow_ui) {
+        CHECK_EXPECT(GetUIBehavior);
+        ok(UicItem == SCRIPTUICITEM_MSGBOX, "UidItem = %d\n", UicItem);
+    }
+    *pUicHandling = uic_handling;
+    return S_OK;
+}
+
+static const IActiveScriptSiteUIControlVtbl ActiveScriptSiteUIControlVtbl = {
+    ActiveScriptSiteUIControl_QueryInterface,
+    ActiveScriptSiteUIControl_AddRef,
+    ActiveScriptSiteUIControl_Release,
+    ActiveScriptSiteUIControl_GetUIBehavior
+};
+
+static IActiveScriptSiteUIControl ActiveScriptSiteUIControl = { &ActiveScriptSiteUIControlVtbl };
+
+static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid))
+        *ppv = iface;
+    else if(IsEqualGUID(&IID_IActiveScriptSite, riid))
+        *ppv = iface;
+    else if(IsEqualGUID(&IID_IActiveScriptSiteWindow, riid))
+        *ppv = &ActiveScriptSiteWindow;
+    else if(IsEqualGUID(&IID_IActiveScriptSiteUIControl, riid))
+        *ppv = &ActiveScriptSiteUIControl;
+    else
+        return E_NOINTERFACE;
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
+{
+    *plcid = GetUserDefaultLCID();
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
+        DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
+{
+    ok(dwReturnMask == SCRIPTINFO_IUNKNOWN, "unexpected dwReturnMask %x\n", dwReturnMask);
+    ok(!ppti, "ppti != NULL\n");
+
+    if(strcmp_wa(pstrName, "test"))
+        ok(0, "unexpected pstrName %s\n", wine_dbgstr_w(pstrName));
+
+    *ppiunkItem = (IUnknown*)&Global;
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
+        const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
+{
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
+{
+    return E_NOTIMPL;
+}
+
+#undef ACTSCPSITE_THIS
+
+static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
+    ActiveScriptSite_QueryInterface,
+    ActiveScriptSite_AddRef,
+    ActiveScriptSite_Release,
+    ActiveScriptSite_GetLCID,
+    ActiveScriptSite_GetItemInfo,
+    ActiveScriptSite_GetDocVersionString,
+    ActiveScriptSite_OnScriptTerminate,
+    ActiveScriptSite_OnStateChange,
+    ActiveScriptSite_OnScriptError,
+    ActiveScriptSite_OnEnterScript,
+    ActiveScriptSite_OnLeaveScript
+};
+
+static IActiveScriptSite ActiveScriptSite = { &ActiveScriptSiteVtbl };
+
+static IActiveScript *create_script(void)
+{
+    IActiveScript *script;
+    HRESULT hres;
+
+    hres = CoCreateInstance(&CLSID_VBScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IActiveScript, (void**)&script);
+    ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
+
+    return script;
+}
+
+static IActiveScript *create_and_init_script(DWORD flags)
+{
+    IActiveScriptParse *parser;
+    IActiveScript *engine;
+    HRESULT hres;
+
+    engine = create_script();
+    if(!engine)
+        return NULL;
+
+    hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
+
+    hres = IActiveScriptParse_InitNew(parser);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+
+    IActiveScriptParse_Release(parser);
+
+    hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+
+    hres = IActiveScript_AddNamedItem(engine, testW,
+            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);
+
+    return engine;
+}
+
+static void close_script(IActiveScript *script)
+{
+    ULONG ref;
+    HRESULT hres;
+
+    hres = IActiveScript_Close(script);
+    ok(hres == S_OK, "Close failed: %08x\n", hres);
+
+    ref = IActiveScript_Release(script);
+    ok(!ref, "ref=%u\n", ref);
+}
+
+static HRESULT parse_script(DWORD flags, BSTR script_str, const WCHAR *delim)
+{
+    IActiveScriptParse *parser;
+    IActiveScript *engine;
+    IDispatch *script_disp;
+    LONG ref;
+    HRESULT hres;
+
+    engine = create_and_init_script(flags);
+    if(!engine)
+        return S_OK;
+
+    hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
+    if (FAILED(hres))
+    {
+        IActiveScript_Release(engine);
+        return hres;
+    }
+
+    hres = IActiveScript_GetScriptDispatch(engine, NULL, &script_disp);
+    ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres);
+    ok(script_disp != NULL, "script_disp == NULL\n");
+    ok(script_disp != (IDispatch*)&Global, "script_disp == Global\n");
+
+    test_counter = 0;
+
+    hres = IActiveScriptParse_ParseScriptText(parser, script_str, NULL, NULL, delim, 0, 0, 0, NULL, NULL);
+
+    IActiveScript_Close(engine);
+
+    IDispatch_Release(script_disp);
+    IActiveScript_Release(engine);
+
+    ref = IActiveScriptParse_Release(parser);
+    ok(!ref, "ref=%d\n", ref);
+    return hres;
+}
+
+static void parse_script_af(DWORD flags, const char *src)
+{
+    BSTR tmp;
+    HRESULT hres;
+
+    tmp = a2bstr(src);
+    hres = parse_script(flags, tmp, NULL);
+    SysFreeString(tmp);
+    ok(hres == S_OK, "parse_script failed: %08x\n", hres);
+}
+
+static HRESULT parse_script_ar(const char *src)
+{
+    BSTR tmp;
+    HRESULT hres;
+
+    tmp = a2bstr(src);
+    hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, tmp, NULL);
+    SysFreeString(tmp);
+    return hres;
+}
+
+static void parse_script_a(const char *src)
+{
+    parse_script_af(SCRIPTITEM_GLOBALMEMBERS, src);
+}
+
+#define parse_htmlscript_a(a) _parse_htmlscript_a(__LINE__,a)
+static void _parse_htmlscript_a(unsigned line, const char *src)
+{
+    BSTR tmp;
+    HRESULT hres;
+
+    static const WCHAR script_delimW[] = {'<','/','S','C','R','I','P','T','>',0};
+
+    tmp = a2bstr(src);
+    hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, tmp, script_delimW);
+    SysFreeString(tmp);
+    ok_(__FILE__,line)(hres == S_OK, "parse_script failed: %08x\n", hres);
+}
+
+static IDispatchEx *parse_procedure(IActiveScriptParseProcedure2 *parse_proc, const char *src)
+{
+    IDispatchEx *dispex;
+    IDispatch *disp;
+    BSTR str;
+    HRESULT hres;
+
+    static const WCHAR delimiterW[] = {'\"',0};
+
+    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);
+    SysFreeString(str);
+    ok(hres == S_OK, "ParseProcedureText failed: %08x\n", hres);
+    ok(disp != NULL, "disp = NULL\n");
+
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    IDispatch_Release(disp);
+    ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres);
+
+    return dispex;
+}
+
+
+static void test_procedures(void)
+{
+    IActiveScriptParseProcedure2 *parse_proc;
+    DISPPARAMS dp = {NULL};
+    IActiveScript *script;
+    IDispatchEx *proc;
+    EXCEPINFO ei = {0};
+    VARIANT v;
+    HRESULT hres;
+
+    script = create_and_init_script(0);
+
+    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");
+
+    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);
+
+    IDispatchEx_Release(proc);
+
+    IActiveScriptParseProcedure2_Release(parse_proc);
+
+    close_script(script);
+}
+
+static void test_gc(void)
+{
+    IActiveScriptParse *parser;
+    IActiveScript *engine;
+    BSTR src;
+    HRESULT hres;
+
+    strict_dispid_check = FALSE;
+
+    engine = create_script();
+    if(!engine)
+        return;
+
+    hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
+
+    hres = IActiveScriptParse_InitNew(parser);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+
+    hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+
+    hres = IActiveScript_AddNamedItem(engine, testW,
+            SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
+    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);
+
+    src = a2bstr(
+            "class C\n"
+            "    Public ref\n"
+            "    Public Sub Class_Terminate\n"
+            "        Call reportSuccess()\n"
+            "    End Sub\n"
+            "End Class\n"
+            "Dim x\n"
+            "set x = new C\n"
+            "set x.ref = x\n"
+            "set x = nothing\n");
+
+    hres = IActiveScriptParse_ParseScriptText(parser, src, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+    SysFreeString(src);
+
+    SET_EXPECT(global_success_d);
+    SET_EXPECT(global_success_i);
+    IActiveScript_Close(engine);
+    CHECK_CALLED(global_success_d);
+    CHECK_CALLED(global_success_i);
+
+    IActiveScript_Release(engine);
+    IActiveScriptParse_Release(parser);
+}
+
+static void test_msgbox(void)
+{
+    HRESULT hres;
+
+    uic_handling = SCRIPTUICHANDLING_NOUIDEFAULT;
+
+    SET_EXPECT(GetUIBehavior);
+    SET_EXPECT(GetWindow);
+    SET_EXPECT(EnableModeless);
+    hres = parse_script_ar("MsgBox \"testing...\"");
+    CLEAR_CALLED(GetUIBehavior);
+    CLEAR_CALLED(GetWindow);
+    CLEAR_CALLED(EnableModeless);
+    if(FAILED(hres)) {
+        win_skip("Skipping MsgBox tests, broken (probably too old) vbscript\n");
+        return;
+    }
+
+    SET_EXPECT(GetUIBehavior);
+    parse_script_a("dim r\n r=MsgBox(\"testing...\")\n Call ok(r=0, \"r=\"&r)");
+    CHECK_CALLED(GetUIBehavior);
+
+    SET_EXPECT(GetUIBehavior);
+    parse_script_a("MsgBox 10");
+    CHECK_CALLED(GetUIBehavior);
+
+    uic_handling = SCRIPTUICHANDLING_ALLOW;
+
+    SET_EXPECT(GetUIBehavior);
+    SET_EXPECT(GetWindow);
+    SET_EXPECT(EnableModeless);
+    hres = parse_script_ar("MsgBox \"testing...\"");
+    ok(FAILED(hres), "script not failed\n");
+    CHECK_CALLED(GetUIBehavior);
+    CHECK_CALLED(GetWindow);
+    CHECK_CALLED(EnableModeless);
+
+    uic_handling = SCRIPTUICHANDLING_NOUIERROR;
+
+    SET_EXPECT(GetUIBehavior);
+    hres = parse_script_ar("MsgBox \"testing...\"");
+    ok(FAILED(hres), "script not failed\n");
+    CHECK_CALLED(GetUIBehavior);
+}
+
+static HRESULT test_global_vars_ref(BOOL use_close)
+{
+    IActiveScriptParse *parser;
+    IActiveScript *engine;
+    BSTR script_str;
+    LONG ref;
+    HRESULT hres;
+
+    engine = create_script();
+    if(!engine)
+        return S_OK;
+
+    hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
+    if (FAILED(hres))
+    {
+        IActiveScript_Release(engine);
+        return hres;
+    }
+
+    hres = IActiveScriptParse_InitNew(parser);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+
+    hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+
+    hres = IActiveScript_AddNamedItem(engine, testW, SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
+    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);
+
+    refobj_ref = 0;
+
+    script_str = a2bstr("Dim x\nset x = RefObj\n");
+    hres = IActiveScriptParse_ParseScriptText(parser, script_str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    SysFreeString(script_str);
+
+    ok(refobj_ref, "refobj_ref = 0\n");
+
+    if(use_close) {
+        hres = IActiveScript_Close(engine);
+        ok(hres == S_OK, "Close failed: %08x\n", hres);
+    }else {
+        hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_UNINITIALIZED);
+        ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
+    }
+
+    ok(!refobj_ref, "refobj_ref = %d\n", refobj_ref);
+
+    IActiveScript_Release(engine);
+
+    ref = IActiveScriptParse_Release(parser);
+    ok(!ref, "ref=%d\n", ref);
+    return hres;
+}
+
+static BSTR get_script_from_file(const char *filename)
+{
+    DWORD size, len;
+    HANDLE file, map;
+    const char *file_map;
+    BSTR ret;
+
+    file = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+    if(file == INVALID_HANDLE_VALUE) {
+        trace("Could not open file: %u\n", GetLastError());
+        return NULL;
+    }
+
+    size = GetFileSize(file, NULL);
+
+    map = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
+    CloseHandle(file);
+    if(map == INVALID_HANDLE_VALUE) {
+        trace("Could not create file mapping: %u\n", GetLastError());
+        return NULL;
+    }
+
+    file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
+    CloseHandle(map);
+    if(!file_map) {
+        trace("MapViewOfFile failed: %u\n", GetLastError());
+        return NULL;
+    }
+
+    len = MultiByteToWideChar(CP_ACP, 0, file_map, size, NULL, 0);
+    ret = SysAllocStringLen(NULL, len);
+    MultiByteToWideChar(CP_ACP, 0, file_map, size, ret, len);
+
+    UnmapViewOfFile(file_map);
+
+    return ret;
+}
+
+static void run_from_file(const char *filename)
+{
+    BSTR script_str;
+    HRESULT hres;
+
+    script_str = get_script_from_file(filename);
+    if(!script_str)
+        return;
+
+    strict_dispid_check = FALSE;
+    hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, script_str, NULL);
+    SysFreeString(script_str);
+    ok(hres == S_OK, "parse_script failed: %08x\n", hres);
+}
+
+static void run_from_res(const char *name)
+{
+    const char *data;
+    DWORD size, len;
+    BSTR str;
+    HRSRC src;
+    HRESULT hres;
+
+    strict_dispid_check = FALSE;
+    test_name = name;
+
+    src = FindResourceA(NULL, name, (LPCSTR)40);
+    ok(src != NULL, "Could not find resource %s\n", name);
+
+    size = SizeofResource(NULL, src);
+    data = LoadResource(NULL, src);
+
+    len = MultiByteToWideChar(CP_ACP, 0, data, size, NULL, 0);
+    str = SysAllocStringLen(NULL, len);
+    MultiByteToWideChar(CP_ACP, 0, data, size, str, len);
+
+    SET_EXPECT(global_success_d);
+    SET_EXPECT(global_success_i);
+    hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, str, NULL);
+    CHECK_CALLED(global_success_d);
+    CHECK_CALLED(global_success_i);
+
+    ok(hres == S_OK, "parse_script failed: %08x\n", hres);
+    SysFreeString(str);
+}
+
+static void run_tests(void)
+{
+    HRESULT hres;
+
+    strict_dispid_check = TRUE;
+
+    parse_script_a("");
+    parse_script_a("' empty ;");
+
+    SET_EXPECT(global_success_d);
+    SET_EXPECT(global_success_i);
+    parse_script_a("reportSuccess");
+    CHECK_CALLED(global_success_d);
+    CHECK_CALLED(global_success_i);
+
+    SET_EXPECT(global_success_d);
+    SET_EXPECT(global_success_i);
+    parse_script_a("reportSuccess()");
+    CHECK_CALLED(global_success_d);
+    CHECK_CALLED(global_success_i);
+
+    SET_EXPECT(global_success_d);
+    SET_EXPECT(global_success_i);
+    parse_script_a("Call reportSuccess");
+    CHECK_CALLED(global_success_d);
+    CHECK_CALLED(global_success_i);
+
+    SET_EXPECT(global_success_d);
+    SET_EXPECT(global_success_i);
+    parse_script_a("test.reportSuccess()");
+    CHECK_CALLED(global_success_d);
+    CHECK_CALLED(global_success_i);
+
+    SET_EXPECT(global_vbvar_d);
+    SET_EXPECT(global_vbvar_i);
+    parse_script_a("Option Explicit\nvbvar = 3");
+    CHECK_CALLED(global_vbvar_d);
+    CHECK_CALLED(global_vbvar_i);
+
+    SET_EXPECT(global_vbvar_d);
+    SET_EXPECT(global_vbvar_i);
+    parse_script_a("Option Explicit\nvbvar() = 3");
+    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");
+    CHECK_CALLED(testobj_propput_d);
+    CHECK_CALLED(testobj_propput_i);
+
+    SET_EXPECT(global_propargput_d);
+    SET_EXPECT(global_propargput_i);
+    parse_script_a("propargput(counter(), counter()) = counter()");
+    CHECK_CALLED(global_propargput_d);
+    CHECK_CALLED(global_propargput_i);
+
+    SET_EXPECT(global_propargput_d);
+    SET_EXPECT(global_propargput_i);
+    parse_script_a("test.propargput(counter(), counter()) = counter()");
+    CHECK_CALLED(global_propargput_d);
+    CHECK_CALLED(global_propargput_i);
+
+    SET_EXPECT(global_propargput1_d);
+    SET_EXPECT(global_propargput1_i);
+    parse_script_a("propargput1 (counter()) = counter()");
+    CHECK_CALLED(global_propargput1_d);
+    CHECK_CALLED(global_propargput1_i);
+
+    SET_EXPECT(global_propargput1_d);
+    SET_EXPECT(global_propargput1_i);
+    parse_script_a("test.propargput1(counter()) = counter()");
+    CHECK_CALLED(global_propargput1_d);
+    CHECK_CALLED(global_propargput1_i);
+
+    parse_htmlscript_a("<!--");
+    parse_htmlscript_a(" -->");
+    parse_htmlscript_a("<!--\ndim x\nx=1\n-->\n");
+    parse_htmlscript_a("<!--\ndim x\n-->\n<!--\nx=1\n-->\n");
+
+    hres = parse_script_ar("<!--");
+    ok(FAILED(hres), "script didn't fail\n");
+
+    SET_EXPECT(global_success_d);
+    SET_EXPECT(global_success_i);
+    parse_htmlscript_a("<!--\n<!-- ignore this <> <>\n--> <>\nCall reportSuccess()\n-->\n");
+    CHECK_CALLED(global_success_d);
+    CHECK_CALLED(global_success_i);
+
+    next_cnt = 0;
+    SET_EXPECT(collectionobj_newenum_i);
+    SET_EXPECT(Next);
+    parse_script_a("for each x in collectionObj\nnext");
+    CHECK_CALLED(collectionobj_newenum_i);
+    CHECK_CALLED(Next);
+    ok(next_cnt == 4, "next_cnt = %d\n", next_cnt);
+
+    parse_script_a("x = 1\n Call ok(x = 1, \"x = \" & x)");
+
+    parse_script_a("x = _    \n3");
+
+    test_global_vars_ref(TRUE);
+    test_global_vars_ref(FALSE);
+
+    strict_dispid_check = FALSE;
+
+    parse_script_a("Sub testsub\n"
+                   "x = 1\n"
+                   "Call ok(x = 1, \"x = \" & x)\n"
+                   "End Sub\n"
+                   "Call testsub()");
+
+    parse_script_a("Call ok(getVT(x) = \"VT_EMPTY*\", \"getVT(x) = \" & getVT(x))\n");
+    parse_script_a("Call ok(x = \"\", \"x = \" & x)\n");
+    parse_script_a("x = y\n"
+                   "Call ok(getVT(x) = \"VT_EMPTY*\", \"getVT(x) = \" & getVT(x))\n"
+                   "Call ok(getVT(y) = \"VT_EMPTY*\", \"getVT(y) = \" & getVT(y))");
+    hres = parse_script_ar("x = y(\"a\")");
+    ok(FAILED(hres), "script didn't fail\n");
+
+    run_from_res("lang.vbs");
+    run_from_res("api.vbs");
+    run_from_res("regexp.vbs");
+
+    test_procedures();
+    test_gc();
+    test_msgbox();
+}
+
+static BOOL check_vbscript(void)
+{
+    IRegExp2 *regexp;
+    IUnknown *unk;
+    HRESULT hres;
+
+    hres = CoCreateInstance(&CLSID_VBScriptRegExp, NULL,
+            CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IUnknown, (void**)&unk);
+    if(hres == REGDB_E_CLASSNOTREG)
+        return FALSE;
+    ok(hres == S_OK, "CoCreateInstance(CLSID_VBScriptRegExp) failed: %x\n", hres);
+
+    hres = IUnknown_QueryInterface(unk, &IID_IRegExp2, (void**)&regexp);
+    if(SUCCEEDED(hres))
+        IRegExp2_Release(regexp);
+    IUnknown_Release(unk);
+
+    return hres == S_OK;
+}
+
+START_TEST(run)
+{
+    int argc;
+    char **argv;
+
+    is_english = is_lang_english();
+    if(!is_english)
+        skip("Skipping some tests in non-English locale\n");
+
+    argc = winetest_get_mainargs(&argv);
+
+    CoInitialize(NULL);
+
+    if(!check_vbscript()) {
+        win_skip("Broken engine, probably too old\n");
+    }else if(argc > 2) {
+        allow_ui = TRUE;
+        uic_handling = SCRIPTUICHANDLING_ALLOW;
+        run_from_file(argv[2]);
+    }else {
+        run_tests();
+    }
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/vbscript/testlist.c b/rostests/winetests/vbscript/testlist.c
new file mode 100644 (file)
index 0000000..92b820a
--- /dev/null
@@ -0,0 +1,16 @@
+/* Automatically generated file; DO NOT EDIT!! */
+
+#define STANDALONE
+#include <wine/test.h>
+
+extern void func_createobj(void);
+extern void func_run(void);
+extern void func_vbscript(void);
+
+const struct test winetest_testlist[] =
+{
+    { "createobj", func_createobj },
+    { "run", func_run },
+    { "vbscript", func_vbscript },
+    { 0, 0 }
+};
diff --git a/rostests/winetests/vbscript/vbscript.c b/rostests/winetests/vbscript/vbscript.c
new file mode 100644 (file)
index 0000000..1996e2b
--- /dev/null
@@ -0,0 +1,968 @@
+/*
+ * Copyright 2011 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+
+#define COBJMACROS
+#define CONST_VTABLE
+
+#include <windef.h>
+#include <winbase.h>
+#include <winnls.h>
+#include <initguid.h>
+#include <ole2.h>
+#include <activscp.h>
+#include <objsafe.h>
+#include <dispex.h>
+
+#include <vbsregexp55.h>
+
+#include <wine/test.h>
+
+#ifdef _WIN64
+
+#define IActiveScriptParse_QueryInterface IActiveScriptParse64_QueryInterface
+#define IActiveScriptParse_Release IActiveScriptParse64_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
+#define IActiveScriptParseProcedure2_Release \
+    IActiveScriptParseProcedure2_64_Release
+
+#else
+
+#define IActiveScriptParse_QueryInterface IActiveScriptParse32_QueryInterface
+#define IActiveScriptParse_Release IActiveScriptParse32_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
+#define IActiveScriptParseProcedure2_Release \
+    IActiveScriptParseProcedure2_32_Release
+
+#endif
+
+DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
+
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+    expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_EXPECT(func) \
+    do { \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+DEFINE_EXPECT(GetLCID);
+DEFINE_EXPECT(OnStateChange_UNINITIALIZED);
+DEFINE_EXPECT(OnStateChange_STARTED);
+DEFINE_EXPECT(OnStateChange_CONNECTED);
+DEFINE_EXPECT(OnStateChange_DISCONNECTED);
+DEFINE_EXPECT(OnStateChange_CLOSED);
+DEFINE_EXPECT(OnStateChange_INITIALIZED);
+DEFINE_EXPECT(OnEnterScript);
+DEFINE_EXPECT(OnLeaveScript);
+
+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);
+
+static BSTR a2bstr(const char *str)
+{
+    BSTR ret;
+    int len;
+
+    len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+    ret = SysAllocStringLen(NULL, len-1);
+    MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
+
+    return ret;
+}
+
+#define test_state(s,ss) _test_state(__LINE__,s,ss)
+static void _test_state(unsigned line, IActiveScript *script, SCRIPTSTATE exstate)
+{
+    SCRIPTSTATE state = -1;
+    HRESULT hres;
+
+    hres = IActiveScript_GetScriptState(script, &state);
+    ok_(__FILE__,line) (hres == S_OK, "GetScriptState failed: %08x\n", hres);
+    ok_(__FILE__,line) (state == exstate, "state=%d, expected %d\n", state, exstate);
+}
+
+static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid))
+        *ppv = iface;
+    else if(IsEqualGUID(&IID_IActiveScriptSite, riid))
+        *ppv = iface;
+    else
+        return E_NOINTERFACE;
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
+{
+    CHECK_EXPECT(GetLCID);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
+        DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
+        const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
+{
+    switch(ssScriptState) {
+    case SCRIPTSTATE_UNINITIALIZED:
+        CHECK_EXPECT(OnStateChange_UNINITIALIZED);
+        return S_OK;
+    case SCRIPTSTATE_STARTED:
+        CHECK_EXPECT(OnStateChange_STARTED);
+        return S_OK;
+    case SCRIPTSTATE_CONNECTED:
+        CHECK_EXPECT(OnStateChange_CONNECTED);
+        return S_OK;
+    case SCRIPTSTATE_DISCONNECTED:
+        CHECK_EXPECT(OnStateChange_DISCONNECTED);
+        return S_OK;
+    case SCRIPTSTATE_CLOSED:
+        CHECK_EXPECT(OnStateChange_CLOSED);
+        return S_OK;
+    case SCRIPTSTATE_INITIALIZED:
+        CHECK_EXPECT(OnStateChange_INITIALIZED);
+        return S_OK;
+    default:
+        ok(0, "unexpected call %d\n", ssScriptState);
+    }
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
+{
+    CHECK_EXPECT(OnEnterScript);
+    return S_OK;
+}
+
+static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
+{
+    CHECK_EXPECT(OnLeaveScript);
+    return S_OK;
+}
+
+static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
+    ActiveScriptSite_QueryInterface,
+    ActiveScriptSite_AddRef,
+    ActiveScriptSite_Release,
+    ActiveScriptSite_GetLCID,
+    ActiveScriptSite_GetItemInfo,
+    ActiveScriptSite_GetDocVersionString,
+    ActiveScriptSite_OnScriptTerminate,
+    ActiveScriptSite_OnStateChange,
+    ActiveScriptSite_OnScriptError,
+    ActiveScriptSite_OnEnterScript,
+    ActiveScriptSite_OnLeaveScript
+};
+
+static IActiveScriptSite ActiveScriptSite = { &ActiveScriptSiteVtbl };
+
+static void test_safety(IActiveScript *script)
+{
+    IObjectSafety *safety;
+    DWORD supported, enabled;
+    HRESULT hres;
+
+    hres = IActiveScript_QueryInterface(script, &IID_IObjectSafety, (void**)&safety);
+    ok(hres == S_OK, "Could not get IObjectSafety: %08x\n", hres);
+    if(FAILED(hres))
+        return;
+
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_NULL, &supported, NULL);
+    ok(hres == E_POINTER, "GetInterfaceSafetyOptions failed: %08x, expected E_POINTER\n", hres);
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_NULL, NULL, &enabled);
+    ok(hres == E_POINTER, "GetInterfaceSafetyOptions failed: %08x, expected E_POINTER\n", hres);
+
+    supported = enabled = 0xdeadbeef;
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_NULL, &supported, &enabled);
+    ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres);
+    ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
+       "supported=%x\n", supported);
+    ok(enabled == INTERFACE_USES_DISPEX, "enabled=%x\n", enabled);
+
+    supported = enabled = 0xdeadbeef;
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScript, &supported, &enabled);
+    ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres);
+    ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
+       "supported=%x\n", supported);
+    ok(enabled == INTERFACE_USES_DISPEX, "enabled=%x\n", enabled);
+
+    supported = enabled = 0xdeadbeef;
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported, &enabled);
+    ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres);
+    ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
+       "supported=%x\n", supported);
+    ok(enabled == INTERFACE_USES_DISPEX, "enabled=%x\n", enabled);
+
+    hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
+            INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER
+                |INTERFACESAFE_FOR_UNTRUSTED_CALLER,
+            INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
+    ok(hres == E_FAIL, "SetInterfaceSafetyOptions failed: %08x, expected E_FAIL\n", hres);
+
+    hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
+            INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER,
+            INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER);
+    ok(hres == S_OK, "SetInterfaceSafetyOptions failed: %08x\n", hres);
+
+    supported = enabled = 0xdeadbeef;
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported, &enabled);
+    ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres);
+    ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
+       "supported=%x\n", supported);
+    ok(enabled == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
+       "enabled=%x\n", enabled);
+
+    hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, INTERFACESAFE_FOR_UNTRUSTED_DATA, 0);
+    ok(hres == S_OK, "SetInterfaceSafetyOptions failed: %08x\n", hres);
+
+    supported = enabled = 0xdeadbeef;
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported, &enabled);
+    ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres);
+    ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
+       "supported=%x\n", supported);
+    ok(enabled == (INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER), "enabled=%x\n", enabled);
+
+    hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
+            INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER, 0);
+    ok(hres == S_OK, "SetInterfaceSafetyOptions failed: %08x\n", hres);
+
+    supported = enabled = 0xdeadbeef;
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported, &enabled);
+    ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres);
+    ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
+       "supported=%x\n", supported);
+    ok(enabled == INTERFACE_USES_DISPEX, "enabled=%x\n", enabled);
+
+    hres = IObjectSafety_SetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse,
+            INTERFACE_USES_DISPEX, 0);
+    ok(hres == S_OK, "SetInterfaceSafetyOptions failed: %08x\n", hres);
+
+    supported = enabled = 0xdeadbeef;
+    hres = IObjectSafety_GetInterfaceSafetyOptions(safety, &IID_IActiveScriptParse, &supported, &enabled);
+    ok(hres == S_OK, "GetInterfaceSafetyOptions failed: %08x\n", hres);
+    ok(supported == (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER),
+       "supported=%x\n", supported);
+    ok(enabled == INTERFACE_USES_DISPEX, "enabled=%x\n", enabled);
+
+    IObjectSafety_Release(safety);
+}
+
+static IDispatchEx *get_script_dispatch(IActiveScript *script)
+{
+    IDispatchEx *dispex;
+    IDispatch *disp;
+    HRESULT hres;
+
+    disp = (void*)0xdeadbeef;
+    hres = IActiveScript_GetScriptDispatch(script, NULL, &disp);
+    ok(hres == S_OK, "GetScriptDispatch failed: %08x\n", hres);
+    if(FAILED(hres))
+        return NULL;
+
+    hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
+    IDispatch_Release(disp);
+    ok(hres == S_OK, "Could not get IDispatchEx iface: %08x\n", hres);
+    return dispex;
+}
+
+static void parse_script(IActiveScriptParse *parse, const char *src)
+{
+    BSTR str;
+    HRESULT hres;
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+
+    str = a2bstr(src);
+    hres = IActiveScriptParse_ParseScriptText(parse, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    SysFreeString(str);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+}
+
+#define get_disp_id(a,b,c,d) _get_disp_id(__LINE__,a,b,c,d)
+static void _get_disp_id(unsigned line, IDispatchEx *dispex, const char *name, HRESULT exhres, DISPID *id)
+{
+    DISPID id2;
+    BSTR str;
+    HRESULT hres;
+
+    str = a2bstr(name);
+    hres = IDispatchEx_GetDispID(dispex, str, 0, id);
+    ok_(__FILE__,line)(hres == exhres, "GetDispID(%s) returned %08x, expected %08x\n", name, hres, exhres);
+
+    hres = IDispatchEx_GetIDsOfNames(dispex, &IID_NULL, &str, 1, 0, &id2);
+    SysFreeString(str);
+    ok_(__FILE__,line)(hres == exhres, "GetIDsOfNames(%s) returned %08x, expected %08x\n", name, hres, exhres);
+    ok_(__FILE__,line)(*id == id2, "GetIDsOfNames(%s) id != id2\n", name);
+}
+
+static void test_no_script_dispatch(IActiveScript *script)
+{
+    IDispatch *disp;
+    HRESULT hres;
+
+    disp = (void*)0xdeadbeef;
+    hres = IActiveScript_GetScriptDispatch(script, NULL, &disp);
+    ok(hres == E_UNEXPECTED, "hres = %08x, expected E_UNEXPECTED\n", hres);
+    ok(!disp, "disp != NULL\n");
+}
+
+static IActiveScript *create_vbscript(void)
+{
+    IActiveScript *ret;
+    HRESULT hres;
+
+    hres = CoCreateInstance(&CLSID_VBScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IActiveScript, (void**)&ret);
+    ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
+
+    return ret;
+}
+
+static void test_scriptdisp(void)
+{
+    IActiveScriptParse *parser;
+    IDispatchEx *script_disp;
+    IActiveScript *vbscript;
+    DISPID id, id2;
+    DISPPARAMS dp;
+    EXCEPINFO ei;
+    VARIANT v;
+    ULONG ref;
+    HRESULT hres;
+
+    vbscript = create_vbscript();
+
+    hres = IActiveScript_QueryInterface(vbscript, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse iface: %08x\n", hres);
+
+    test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
+    test_safety(vbscript);
+
+    SET_EXPECT(GetLCID);
+    hres = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+    CHECK_CALLED(GetLCID);
+
+    test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
+
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScriptParse_InitNew(parser);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    test_state(vbscript, SCRIPTSTATE_INITIALIZED);
+
+    SET_EXPECT(OnStateChange_CONNECTED);
+    hres = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_CONNECTED);
+
+    test_state(vbscript, SCRIPTSTATE_CONNECTED);
+
+    script_disp = get_script_dispatch(vbscript);
+
+    id = 100;
+    get_disp_id(script_disp, "LCase", DISP_E_UNKNOWNNAME, &id);
+    ok(id == -1, "id = %d, expected -1\n", id);
+
+    get_disp_id(script_disp, "globalVariable", DISP_E_UNKNOWNNAME, &id);
+    parse_script(parser, "dim globalVariable\nglobalVariable = 3");
+    get_disp_id(script_disp, "globalVariable", S_OK, &id);
+
+    memset(&dp, 0, sizeof(dp));
+    memset(&ei, 0, sizeof(ei));
+    V_VT(&v) = VT_EMPTY;
+    hres = IDispatchEx_InvokeEx(script_disp, 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) == 3, "V_I2(v) = %d\n", V_I2(&v));
+
+    get_disp_id(script_disp, "globalVariable2", DISP_E_UNKNOWNNAME, &id);
+    parse_script(parser, "globalVariable2 = 4");
+    get_disp_id(script_disp, "globalVariable2", S_OK, &id);
+
+    get_disp_id(script_disp, "globalFunction", DISP_E_UNKNOWNNAME, &id);
+    parse_script(parser, "function globalFunction()\nglobalFunction=5\nend function");
+    get_disp_id(script_disp, "globalFunction", S_OK, &id);
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+
+    memset(&dp, 0, sizeof(dp));
+    memset(&ei, 0, sizeof(ei));
+    V_VT(&v) = VT_EMPTY;
+    hres = IDispatchEx_InvokeEx(script_disp, 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) == 5, "V_I2(v) = %d\n", V_I2(&v));
+
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+
+    memset(&dp, 0, sizeof(dp));
+    memset(&ei, 0, sizeof(ei));
+    V_VT(&v) = VT_EMPTY;
+    hres = IDispatchEx_Invoke(script_disp, id, &IID_NULL, 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) == 5, "V_I2(v) = %d\n", V_I2(&v));
+
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+
+    get_disp_id(script_disp, "globalSub", DISP_E_UNKNOWNNAME, &id);
+    parse_script(parser, "sub globalSub()\nend sub");
+    get_disp_id(script_disp, "globalSub", S_OK, &id);
+    get_disp_id(script_disp, "globalSub", S_OK, &id2);
+    ok(id == id2, "id != id2\n");
+
+    get_disp_id(script_disp, "constVariable", DISP_E_UNKNOWNNAME, &id);
+    parse_script(parser, "const constVariable = 6");
+    get_disp_id(script_disp, "ConstVariable", S_OK, &id);
+    get_disp_id(script_disp, "Constvariable", S_OK, &id2);
+    ok(id == id2, "id != id2\n");
+
+    IDispatchEx_Release(script_disp);
+
+    IActiveScriptParse_Release(parser);
+
+    SET_EXPECT(OnStateChange_DISCONNECTED);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    SET_EXPECT(OnStateChange_CLOSED);
+    hres = IActiveScript_Close(vbscript);
+    ok(hres == S_OK, "Close failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_DISCONNECTED);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+    CHECK_CALLED(OnStateChange_CLOSED);
+
+    ref = IActiveScript_Release(vbscript);
+    ok(!ref, "ref = %d\n", ref);
+}
+
+static void test_vbscript(void)
+{
+    IActiveScriptParseProcedure2 *parse_proc;
+    IActiveScriptParse *parser;
+    IActiveScript *vbscript;
+    ULONG ref;
+    HRESULT hres;
+
+    vbscript = create_vbscript();
+
+    hres = IActiveScript_QueryInterface(vbscript, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse iface: %08x\n", hres);
+
+    test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
+    test_safety(vbscript);
+
+    SET_EXPECT(GetLCID);
+    hres = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+    CHECK_CALLED(GetLCID);
+
+    test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
+
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScriptParse_InitNew(parser);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    test_state(vbscript, SCRIPTSTATE_INITIALIZED);
+
+    hres = IActiveScriptParse_InitNew(parser);
+    ok(hres == E_UNEXPECTED, "InitNew failed: %08x, expected E_UNEXPECTED\n", hres);
+
+    SET_EXPECT(OnStateChange_CONNECTED);
+    hres = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_CONNECTED);
+
+    test_state(vbscript, SCRIPTSTATE_CONNECTED);
+
+    SET_EXPECT(OnStateChange_DISCONNECTED);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    SET_EXPECT(OnStateChange_CLOSED);
+    hres = IActiveScript_Close(vbscript);
+    ok(hres == S_OK, "Close failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_DISCONNECTED);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+    CHECK_CALLED(OnStateChange_CLOSED);
+
+    test_state(vbscript, SCRIPTSTATE_CLOSED);
+    test_no_script_dispatch(vbscript);
+
+    IActiveScriptParse_Release(parser);
+
+    hres = IActiveScript_QueryInterface(vbscript, &IID_IActiveScriptParseProcedure, (void**)&parse_proc);
+    ok(hres == E_NOINTERFACE, "Got IActiveScriptParseProcedure interface, expected E_NOTIMPL\n");
+
+    hres = IActiveScript_QueryInterface(vbscript, &IID_IActiveScriptParseProcedure2, (void**)&parse_proc);
+    ok(hres == S_OK, "Could not get IActiveScriptParseProcedure2 interface\n");
+    IActiveScriptParseProcedure2_Release(parse_proc);
+
+    ref = IActiveScript_Release(vbscript);
+    ok(!ref, "ref = %d\n", ref);
+}
+
+static void test_vbscript_uninitializing(void)
+{
+    IActiveScriptParse *parse;
+    IActiveScript *script;
+    IDispatchEx *dispex;
+    ULONG ref;
+    HRESULT hres;
+
+    static const WCHAR script_textW[] =
+        {'F','u','n','c','t','i','o','n',' ','f','\n','E','n','d',' ','F','u','n','c','t','i','o','n','\n',0};
+
+    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 = IActiveScriptParse_InitNew(parse);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+
+    SET_EXPECT(GetLCID);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+    CHECK_CALLED(GetLCID);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    test_state(script, SCRIPTSTATE_INITIALIZED);
+
+    hres = IActiveScriptParse_ParseScriptText(parse, script_textW, NULL, NULL, NULL, 0, 1, 0x42, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
+
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == E_UNEXPECTED, "SetScriptSite failed: %08x, expected E_UNEXPECTED\n", hres);
+
+    SET_EXPECT(OnStateChange_UNINITIALIZED);
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_UNINITIALIZED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_UNINITIALIZED);
+
+    test_state(script, SCRIPTSTATE_UNINITIALIZED);
+
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_UNINITIALIZED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hres);
+
+    SET_EXPECT(GetLCID);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+    CHECK_CALLED(GetLCID);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    SET_EXPECT(OnStateChange_CONNECTED);
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_CONNECTED);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+
+    test_state(script, SCRIPTSTATE_CONNECTED);
+
+    dispex = get_script_dispatch(script);
+    ok(dispex != NULL, "dispex == NULL\n");
+    if(dispex)
+        IDispatchEx_Release(dispex);
+
+    SET_EXPECT(OnStateChange_DISCONNECTED);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    SET_EXPECT(OnStateChange_UNINITIALIZED);
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_UNINITIALIZED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_DISCONNECTED);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+    CHECK_CALLED(OnStateChange_UNINITIALIZED);
+
+    test_state(script, SCRIPTSTATE_UNINITIALIZED);
+
+    hres = IActiveScript_Close(script);
+    ok(hres == S_OK, "Close failed: %08x\n", hres);
+
+    test_state(script, SCRIPTSTATE_CLOSED);
+
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_UNINITIALIZED);
+    ok(hres == E_UNEXPECTED, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x, expected E_UNEXPECTED\n", hres);
+
+    test_state(script, SCRIPTSTATE_CLOSED);
+
+    SET_EXPECT(GetLCID);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+    CHECK_CALLED(GetLCID);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    test_state(script, SCRIPTSTATE_INITIALIZED);
+
+    SET_EXPECT(OnStateChange_CLOSED);
+    hres = IActiveScript_Close(script);
+    ok(hres == S_OK, "Close failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_CLOSED);
+
+    test_state(script, SCRIPTSTATE_CLOSED);
+
+    IActiveScriptParse_Release(parse);
+
+    ref = IActiveScript_Release(script);
+    ok(!ref, "ref = %d\n", ref);
+}
+
+static void test_vbscript_release(void)
+{
+    IActiveScriptParse *parser;
+    IActiveScript *vbscript;
+    ULONG ref;
+    HRESULT hres;
+
+    vbscript = create_vbscript();
+
+    hres = IActiveScript_QueryInterface(vbscript, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse iface: %08x\n", hres);
+
+    test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
+    test_safety(vbscript);
+
+    SET_EXPECT(GetLCID);
+    hres = IActiveScript_SetScriptSite(vbscript, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+    CHECK_CALLED(GetLCID);
+
+    test_state(vbscript, SCRIPTSTATE_UNINITIALIZED);
+
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScriptParse_InitNew(parser);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    test_state(vbscript, SCRIPTSTATE_INITIALIZED);
+
+    SET_EXPECT(OnStateChange_CONNECTED);
+    hres = IActiveScript_SetScriptState(vbscript, SCRIPTSTATE_CONNECTED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_CONNECTED) failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_CONNECTED);
+
+    test_state(vbscript, SCRIPTSTATE_CONNECTED);
+
+    IActiveScriptParse_Release(parser);
+
+    SET_EXPECT(OnStateChange_DISCONNECTED);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    SET_EXPECT(OnStateChange_CLOSED);
+    ref = IActiveScript_Release(vbscript);
+    ok(!ref, "ref = %d\n", ref);
+    CHECK_CALLED(OnStateChange_DISCONNECTED);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+    CHECK_CALLED(OnStateChange_CLOSED);
+}
+
+static void test_vbscript_simplecreate(void)
+{
+    IActiveScript *script;
+    ULONG ref;
+    HRESULT hres;
+
+    script = create_vbscript();
+
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_UNINITIALIZED);
+    ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_UNINITIALIZED) failed: %08x\n", hres);
+
+    ref = IActiveScript_Release(script);
+    ok(!ref, "ref = %d\n", ref);
+}
+
+static void test_vbscript_initializing(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);
+
+    SET_EXPECT(GetLCID);
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
+    CHECK_CALLED(GetLCID);
+
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScriptParse_InitNew(parse);
+    ok(hres == S_OK, "InitNew failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == E_UNEXPECTED, "SetScriptSite failed: %08x, expected E_UNEXPECTED\n", hres);
+
+    SET_EXPECT(OnStateChange_CLOSED);
+    hres = IActiveScript_Close(script);
+    ok(hres == S_OK, "Close failed: %08x\n", hres);
+    CHECK_CALLED(OnStateChange_CLOSED);
+
+    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;
+    IMatchCollection2 *mc;
+    IMatch2 *match;
+    ISubMatches *sm;
+    IEnumVARIANT *ev;
+    IUnknown *unk;
+    IDispatch *disp;
+    HRESULT hres;
+    BSTR bstr;
+    LONG count;
+    VARIANT v;
+    ULONG fetched;
+
+    hres = CoCreateInstance(&CLSID_VBScriptRegExp, NULL,
+            CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IUnknown, (void**)&unk);
+    if(hres == REGDB_E_CLASSNOTREG) {
+        win_skip("VBScriptRegExp is not registered\n");
+        return;
+    }
+    ok(hres == S_OK, "CoCreateInstance(CLSID_VBScriptRegExp) failed: %x\n", hres);
+
+    hres = IUnknown_QueryInterface(unk, &IID_IRegExp2, (void**)&regexp);
+    if(hres == E_NOINTERFACE) {
+        win_skip("IRegExp2 interface is not available\n");
+        return;
+    }
+    ok(hres == S_OK, "QueryInterface(IID_IRegExp2) failed: %x\n", hres);
+    IUnknown_Release(unk);
+
+    hres = IRegExp2_QueryInterface(regexp, &IID_IRegExp, (void**)&unk);
+    ok(hres == S_OK, "QueryInterface(IID_IRegExp) returned %x\n", hres);
+    IUnknown_Release(unk);
+
+    hres = IRegExp2_QueryInterface(regexp, &IID_IDispatchEx, (void**)&unk);
+    ok(hres == E_NOINTERFACE, "QueryInterface(IID_IDispatchEx) returned %x\n", hres);
+
+    hres = IRegExp2_get_Pattern(regexp, &bstr);
+    ok(bstr == NULL, "bstr != NULL\n");
+    ok(hres == S_OK, "get_Pattern returned %x, expected S_OK\n", hres);
+
+    hres = IRegExp2_get_Pattern(regexp, NULL);
+    ok(hres == E_POINTER, "get_Pattern returned %x, expected E_POINTER\n", hres);
+
+    hres = IRegExp2_get_IgnoreCase(regexp, NULL);
+    ok(hres == E_POINTER, "get_IgnoreCase returned %x, expected E_POINTER\n", hres);
+
+    hres = IRegExp2_get_Global(regexp, NULL);
+    ok(hres == E_POINTER, "get_Global returned %x, expected E_POINTER\n", hres);
+
+    hres = IRegExp2_Execute(regexp, NULL, &disp);
+    ok(hres == S_OK, "Execute returned %x, expected S_OK\n", hres);
+    hres = IDispatch_QueryInterface(disp, &IID_IMatchCollection2, (void**)&mc);
+    ok(hres == S_OK, "QueryInterface(IID_IMatchCollection2) returned %x\n", hres);
+    IDispatch_Release(disp);
+
+    hres = IMatchCollection2_get_Count(mc, NULL);
+    ok(hres == E_POINTER, "get_Count returned %x, expected E_POINTER\n", hres);
+
+    hres = IMatchCollection2_get_Count(mc, &count);
+    ok(hres == S_OK, "get_Count returned %x, expected S_OK\n", hres);
+    ok(count == 1, "count = %d\n", count);
+
+    hres = IMatchCollection2_get_Item(mc, 1, &disp);
+    ok(hres == E_INVALIDARG, "get_Item returned %x, expected E_INVALIDARG\n", hres);
+
+    hres = IMatchCollection2_get_Item(mc, 1, NULL);
+    ok(hres == E_POINTER, "get_Item returned %x, expected E_POINTER\n", hres);
+
+    hres = IMatchCollection2_get_Item(mc, 0, &disp);
+    ok(hres == S_OK, "get_Item returned %x, expected S_OK\n", hres);
+    hres = IDispatch_QueryInterface(disp, &IID_IMatch2, (void**)&match);
+    ok(hres == S_OK, "QueryInterface(IID_IMatch2) returned %x\n", hres);
+    IDispatch_Release(disp);
+
+    hres = IMatch2_get_Value(match, NULL);
+    ok(hres == E_POINTER, "get_Value returned %x, expected E_POINTER\n", hres);
+
+    hres = IMatch2_get_FirstIndex(match, NULL);
+    ok(hres == E_POINTER, "get_FirstIndex returned %x, expected E_POINTER\n", hres);
+
+    hres = IMatch2_get_Length(match, NULL);
+    ok(hres == E_POINTER, "get_Length returned %x, expected E_POINTER\n", hres);
+
+    hres = IMatch2_get_SubMatches(match, NULL);
+    ok(hres == E_POINTER, "get_SubMatches returned %x, expected E_POINTER\n", hres);
+
+    hres = IMatch2_get_SubMatches(match, &disp);
+    ok(hres == S_OK, "get_SubMatches returned %x, expected S_OK\n", hres);
+    IMatch2_Release(match);
+    hres = IDispatch_QueryInterface(disp, &IID_ISubMatches, (void**)&sm);
+    ok(hres == S_OK, "QueryInterface(IID_ISubMatches) returned %x\n", hres);
+    IDispatch_Release(disp);
+
+    hres = ISubMatches_get_Item(sm, 0, &v);
+    ok(hres == E_INVALIDARG, "get_Item returned %x, expected E_INVALIDARG\n", hres);
+
+    hres = ISubMatches_get_Item(sm, 0, NULL);
+    ok(hres == E_POINTER, "get_Item returned %x, expected E_POINTER\n", hres);
+
+    hres = ISubMatches_get_Count(sm, NULL);
+    ok(hres == E_POINTER, "get_Count returned %x, expected E_POINTER\n", hres);
+    ISubMatches_Release(sm);
+
+    hres = IMatchCollection2_get__NewEnum(mc, &unk);
+    ok(hres == S_OK, "get__NewEnum returned %x, expected S_OK\n", hres);
+    hres = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void**)&ev);
+    ok(hres == S_OK, "QueryInterface(IID_IEnumVARIANT) returned %x\n", hres);
+    IUnknown_Release(unk);
+    IMatchCollection2_Release(mc);
+
+    hres = IEnumVARIANT_Skip(ev, 2);
+    ok(hres == S_OK, "Skip returned %x\n", hres);
+
+    hres = IEnumVARIANT_Next(ev, 1, &v, &fetched);
+    ok(hres == S_FALSE, "Next returned %x, expected S_FALSE\n", hres);
+    ok(fetched == 0, "fetched = %d\n", fetched);
+
+    hres = IEnumVARIANT_Skip(ev, -1);
+    ok(hres == S_OK, "Skip returned %x\n", hres);
+
+    hres = IEnumVARIANT_Next(ev, 1, &v, &fetched);
+    ok(hres == S_OK, "Next returned %x\n", hres);
+    ok(fetched == 1, "fetched = %d\n", fetched);
+    VariantClear(&v);
+    IEnumVARIANT_Release(ev);
+
+    IRegExp2_Release(regexp);
+}
+
+static BOOL check_vbscript(void)
+{
+    IActiveScriptParseProcedure2 *vbscript;
+    HRESULT hres;
+
+    hres = CoCreateInstance(&CLSID_VBScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
+            &IID_IActiveScriptParseProcedure2, (void**)&vbscript);
+    if(SUCCEEDED(hres))
+        IActiveScriptParseProcedure2_Release(vbscript);
+
+    return hres == S_OK;
+}
+
+START_TEST(vbscript)
+{
+    CoInitialize(NULL);
+
+    if(check_vbscript()) {
+        test_vbscript();
+        test_vbscript_uninitializing();
+        test_vbscript_release();
+        test_vbscript_simplecreate();
+        test_vbscript_initializing();
+        test_scriptdisp();
+        test_RegExp();
+    }else {
+        win_skip("VBScript engine not available or too old\n");
+    }
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/vbscript/vbscript_defs.h b/rostests/winetests/vbscript/vbscript_defs.h
new file mode 100644 (file)
index 0000000..3af86c3
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define DISPID_SUBMATCHES_COUNT     1
+
+#define DISPID_MATCHCOLLECTION_COUNT    1
+
+#define DISPID_MATCH_FIRSTINDEX     10001
+#define DISPID_MATCH_LENGTH         10002
+#define DISPID_MATCH_SUBMATCHES     10003
+
+#define DISPID_REGEXP_PATTERN       10001
+#define DISPID_REGEXP_IGNORECASE    10002
+#define DISPID_REGEXP_GLOBAL        10003
+#define DISPID_REGEXP_EXECUTE       10004
+#define DISPID_REGEXP_TEST          10005
+#define DISPID_REGEXP_REPLACE       10006
+#define DISPID_REGEXP_MULTILINE     10007
diff --git a/rostests/winetests/vbscript/vbsregexp55.idl b/rostests/winetests/vbscript/vbsregexp55.idl
new file mode 100644 (file)
index 0000000..b6934e0
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2013 Piotr Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "oaidl.idl";
+
+#include "vbscript_defs.h"
+
+[
+    helpstring("Microsoft VBScript Regular Expressions 5.5"),
+    uuid(3f4daca7-160d-11d2-a8e9-00104b365c9f),
+    version(5.5)
+]
+library VBScript_RegExp_55
+{
+    importlib("stdole2.tlb");
+
+    [
+        dual,
+        hidden,
+        nonextensible,
+        odl,
+        oleautomation,
+        uuid(3f4daca0-160d-11d2-a8e9-00104b365c9f),
+    ]
+    interface IRegExp : IDispatch
+    {
+        [id(DISPID_REGEXP_PATTERN), propget]
+        HRESULT Pattern([out, retval] BSTR *pPattern);
+
+        [id(DISPID_REGEXP_PATTERN), propput]
+        HRESULT Pattern([in] BSTR pPattern);
+
+        [id(DISPID_REGEXP_IGNORECASE), propget]
+        HRESULT IgnoreCase([out, retval] VARIANT_BOOL *pIgnoreCase);
+
+        [id(DISPID_REGEXP_IGNORECASE), propput]
+        HRESULT IgnoreCase([in] VARIANT_BOOL pIgnoreCase);
+
+        [id(DISPID_REGEXP_GLOBAL), propget]
+        HRESULT Global([out, retval] VARIANT_BOOL *pGlobal);
+
+        [id(DISPID_REGEXP_GLOBAL), propput]
+        HRESULT Global([in] VARIANT_BOOL pGlobal);
+
+        [id(DISPID_REGEXP_EXECUTE)]
+        HRESULT Execute(
+                [in] BSTR sourceString,
+                [out, retval] IDispatch **ppMatches);
+
+        [id(DISPID_REGEXP_TEST)]
+        HRESULT Test(
+                [in] BSTR sourceString,
+                [out, retval] VARIANT_BOOL *pMatch);
+
+        [id(DISPID_REGEXP_REPLACE)]
+        HRESULT Replace(
+                [in] BSTR sourceString,
+                [in] BSTR replaceString,
+                [out, retval] BSTR *pDestString);
+    }
+
+    [
+        dual,
+        hidden,
+        nonextensible,
+        odl,
+        oleautomation,
+        uuid(3f4dacb0-160d-11d2-a8e9-00104b365c9f)
+    ]
+    interface IRegExp2 : IDispatch
+    {
+        [id(DISPID_REGEXP_PATTERN), propget]
+        HRESULT Pattern([out, retval] BSTR *pPattern);
+
+        [id(DISPID_REGEXP_PATTERN), propput]
+        HRESULT Pattern([in] BSTR pPattern);
+
+        [id(DISPID_REGEXP_IGNORECASE), propget]
+        HRESULT IgnoreCase([out, retval] VARIANT_BOOL *pIgnoreCase);
+
+        [id(DISPID_REGEXP_IGNORECASE), propput]
+        HRESULT IgnoreCase([in] VARIANT_BOOL pIgnoreCase);
+
+        [id(DISPID_REGEXP_GLOBAL), propget]
+        HRESULT Global([out, retval] VARIANT_BOOL *pGlobal);
+
+        [id(DISPID_REGEXP_GLOBAL), propput]
+        HRESULT Global([in] VARIANT_BOOL pGlobal);
+
+        [id(DISPID_REGEXP_MULTILINE), propget]
+        HRESULT Multiline([out, retval] VARIANT_BOOL *pMultiline);
+
+        [id(DISPID_REGEXP_MULTILINE), propput]
+        HRESULT Multiline([in] VARIANT_BOOL pMultiline);
+
+        [id(DISPID_REGEXP_EXECUTE)]
+        HRESULT Execute(
+                [in] BSTR sourceString,
+                [out, retval] IDispatch **ppMatches);
+
+        [id(DISPID_REGEXP_TEST)]
+        HRESULT Test(
+                [in] BSTR sourceString,
+                [out, retval] VARIANT_BOOL *pMatch);
+
+        [id(DISPID_REGEXP_REPLACE)]
+        HRESULT Replace(
+                [in] BSTR sourceString,
+                [in] VARIANT replaceVar,
+                [out, retval] BSTR *pDestString);
+    }
+
+    [
+        dual,
+        hidden,
+        nonextensible,
+        odl,
+        oleautomation,
+        uuid(3f4daca1-160d-11d2-a8e9-00104b365c9f)
+    ]
+    interface IMatch : IDispatch
+    {
+        [id(DISPID_VALUE), propget]
+        HRESULT Value([out, retval] BSTR *pValue);
+
+        [id(DISPID_MATCH_FIRSTINDEX), propget]
+        HRESULT FirstIndex([out, retval] LONG *pFirstIndex);
+
+        [id(DISPID_MATCH_LENGTH), propget]
+        HRESULT Length([out, retval] LONG *pLength);
+    }
+
+    [
+        odl,
+        uuid(3f4dacb1-160d-11d2-a8e9-00104b365c9f),
+        hidden,
+        dual,
+        nonextensible,
+        oleautomation
+    ]
+    interface IMatch2 : IDispatch
+    {
+        [id(DISPID_VALUE), propget]
+        HRESULT Value([out, retval] BSTR *pValue);
+
+        [id(DISPID_MATCH_FIRSTINDEX), propget]
+        HRESULT FirstIndex([out, retval] LONG *pFirstIndex);
+
+        [id(DISPID_MATCH_LENGTH), propget]
+        HRESULT Length([out, retval] LONG *pLength);
+
+        [id(DISPID_MATCH_SUBMATCHES), propget]
+        HRESULT SubMatches([out, retval] IDispatch **ppSubMatches);
+    }
+
+    [
+        dual,
+        hidden,
+        nonextensible,
+        odl,
+        oleautomation,
+        uuid(3f4daca2-160d-11d2-a8e9-00104b365c9f)
+    ]
+    interface IMatchCollection : IDispatch
+    {
+        [id(DISPID_VALUE), propget]
+        HRESULT Item(
+                [in] LONG index,
+                [out, retval] IDispatch **ppMatch);
+
+        [id(DISPID_MATCHCOLLECTION_COUNT), propget]
+        HRESULT Count([out, retval] LONG *pCount);
+
+        [id(DISPID_NEWENUM), propget]
+        HRESULT _NewEnum([out, retval] IUnknown **ppEnum);
+    }
+
+    [
+        dual,
+        hidden,
+        nonextensible,
+        odl,
+        oleautomation,
+        uuid(3f4dacb2-160d-11d2-a8e9-00104b365c9f)
+    ]
+    interface IMatchCollection2 : IDispatch
+    {
+        [id(DISPID_VALUE), propget]
+        HRESULT Item(
+                [in] LONG index,
+                [out, retval] IDispatch **ppMatch);
+
+        [id(DISPID_MATCHCOLLECTION_COUNT), propget]
+        HRESULT Count([out, retval] LONG *pCount);
+
+        [id(DISPID_NEWENUM), propget]
+        HRESULT _NewEnum([out, retval] IUnknown **ppEnum);
+    }
+
+    [
+        dual,
+        hidden,
+        nonextensible,
+        odl,
+        oleautomation,
+        uuid(3f4dacb3-160d-11d2-a8e9-00104b365c9f)
+    ]
+    interface ISubMatches : IDispatch
+    {
+        [id(DISPID_VALUE), propget]
+        HRESULT Item(
+                [in] LONG index,
+                [out, retval] VARIANT *pSubMatch);
+
+        [id(DISPID_SUBMATCHES_COUNT), propget]
+        HRESULT Count([out, retval] LONG *pCount);
+
+        [id(DISPID_NEWENUM), propget]
+        HRESULT _NewEnum([out, retval] IUnknown **ppEnum);
+    }
+
+    [
+        uuid(3f4daca4-160d-11d2-a8e9-00104b365c9f)
+    ]
+    coclass RegExp
+    {
+        [default] interface IRegExp2;
+    }
+
+    [
+        noncreatable,
+        uuid(3f4daca5-160d-11d2-a8e9-00104b365c9f)
+    ]
+    coclass Match
+    {
+        [default] interface IMatch2;
+    }
+
+    [
+        noncreatable,
+        uuid(3f4daca6-160d-11d2-a8e9-00104b365c9f)
+    ]
+    coclass MatchCollection
+    {
+        [default] interface IMatchCollection2;
+    }
+
+    [
+        noncreatable,
+        uuid(3f4dacc0-160d-11d2-a8e9-00104b365c9f)
+    ]
+    coclass SubMatches {
+        [default] interface ISubMatches;
+    }
+}