列出对象方法和属性



是否有办法列出在VBS中创建对象的可用方法?

例如:

Set IE = CreateObject("InternetExplorer.Application")

我想列出这个对象的可用属性,如:

IE.AddressBar
IE.Application
IE.Busy
...

或方法:

IE.ClientToWindow
IE.ExecWB
IE.GetProperty
...

如何在VBS中发现任意有效对象的可用属性?

使用tlbinf32.dll中的TypeLib Information Objects可以列出一个类的所有成员。

子> <' tlbinf32.dll '是*Visual Studio 6.0*的一部分,它是2000年左右发布的最新版本。微软似乎不再提供DLL下载了(2017年年中),但你可以从互联网上的各个网站下载。我在https://www.dll4free.com/tlbinf32.dll.html或其他网站上找到了版本*1.1.88.4,Build 8804,版权为Matthew Curland 1996, Microsoft 1997-2000,大小为148.480字节*。子> <要在Win32中安装DLL,请将其复制到'> <要在Win64中安装DLL,请将其复制到'>

下面的脚本演示了包含的函数VariableInfo,它将返回具有传递变量类型的字符串,并且在对象的情况下,所有成员的详细信息,包括Property的类型,可调用类型(SubFunction),以及函数的参数名称和返回类型。在COM对象的情况下,对象的类型名称将是实现的接口的名称。不确定它是否适用于多个实现的接口,但我敢肯定,通过COM在一个类中实现多个接口是不可能的。

不支持任何形式的递归,因为这将导致某些类型的无限循环。

这个将给你几乎完全工作的反射在VBS中。非常适合探索api,例如使用Microsoft Script Debugger

' Reflection for VBScript via tlbinfo32.dll
'
' Patrick Strasser-Mikhail 2017-2021
' Ansgar Wiechers 2019
' https://stackoverflow.com/questions/14305750/list-object-methods-and-properties/44459670#44459670
'
' v1.1 2021-02-01: Show values of arrays and objects, but only one level

' Returns a String describing the passed object/variable on the first level,
' no recursion.
Function VariableInfo(obj)
    VariableInfo = VariableInfoToLevel(obj, 0, 1)
End Function
' Returns a String describing the passed object/variable on the first level,
' recurse down to level max_level(0=no recursion).
Function VariableInfoToLevel(obj, level, max_level)
    Const invokeKindPropertyGet = 0     ' simple data member
    Const invokeKindFunction = 1        ' method: Sub or Function
    Const invokeKindPropertyPut = 2     ' Docs: has a value setter; reality: more like is settable
    Const invokeKindPropertyPutRef = 4  ' Docs: has a reference setter; reality: more like is not settable
    If level > max_level Then
        VariableInfoToLevel = ""
        Exit Function
    End If
    Dim indent : indent = Space(4 * level)
    VariableInfoToLevel = indent
    If isEmpty(obj) Or _
       isNull(obj) _
    Then
        VariableInfoToLevel = VariableInfoToLevel & TypeNameFromVarType(VarType(obj))
    ElseIf Not IsObject(obj) Then
        If Not isArray(obj) Then
            VariableInfoToLevel = indent & TypeNameFromVarType(VarType(obj)) & ", Value: [" & obj & "]"
        Else
            VariableInfoToLevel = indent & TypeNameFromVarType(VarType(obj))
            Dim dimension
            ReDim sizes(0)
            Dim size
            On Error Resume Next
            Err.Clear
            For dimension = 0 To 10 ' deliberate limit to prevent infinite loop
                size = Ubound(obj, dimension + 1)
                If Err.Number <> 0 Then
                    ' report ther then Index out of Bounds
                    If Err.Number <> 9 Then 
                        WScript.Echo "Exception " & Err.Number & ": " & Err.Description & "; in " & Err.Source
                    End If
                    Exit For
                End If
                ReDim Preserve sizes(dimension)
                sizes(dimension) = size  
            Next
            On Error Goto 0
            VariableInfoToLevel = VariableInfoToLevel & "(" & Join(sizes, ",") & ")"
            Select Case dimension
              Case 1
                VariableInfoToLevel = VariableInfoToLevel & " {"  & vbCrlf
                Dim idx
                For idx = LBound(obj) To UBound(obj)
                    VariableInfoToLevel = VariableInfoToLevel & indent & _
                        "     " & idx & ":" & _
                        Trim(VariableInfoToLevel(obj(idx), level + 1, max_level)) & vbCrlf
                Next
                VariableInfoToLevel = VariableInfoToLevel & indent & "}" & vbCrlf
                
              Case 2
                VariableInfoToLevel = indent & "{" & vbCrlf
                Dim idx1, idx2
                For idx1 = LBound(obj, 1) To UBound(obj, 1)
                    For idx2 = LBound(obj, 2) To UBound(obj, 2)
                        VariableInfoToLevel = VariableInfoToLevel & indent & _
                            "     " & idx1 & "," & idx2 & ":" & _
                            Trim(VariableInfoToLevel(obj(idx1, idx2), level + 1, max_level)) & vbCrlf
                    Next
                Next
                VariableInfoToLevel = VariableInfoToLevel & indent & "    }" & vbCrlf
              
              Case Else
                ' 0 is empty anyway, more is too complicated to print, just leave it for now
            End Select
        End If
    ElseIf TypeName(obj) = "Nothing" Then
        VariableInfoToLevel = indent & "Nothing (The Invalid Object)"
    Else
        ' Object
        VariableInfoToLevel = indent & "Object " & TypeName(obj)
        '' Need to think about that... True for Err, but not for System.Dictionary
        '' Seems Err is very special, and we should compare explicitly with internal/predifined Objects (Err, WScript)
        'If varType(obj) <> vbObject Then
            ' hm, interresting...
        '   VariableInfoToLevel = VariableInfoToLevel & " with default property (no analysis possible)"
        '   Exit Function
        'End If
            
        Dim TLI
        Dim MemberInfo
        Dim TypeInfo
        Set TLI = CreateObject("TLI.TLIApplication")
        VariableInfoToLevel = indent & "Object " & TypeName(obj)
        On Error Resume Next
        Err.Clear
        Set TypeInfo = TLI.InterfaceInfoFromObject(obj)
        
        If Err.Number <> 0 Then
            
            VariableInfoToLevel = VariableInfoToLevel & "; Error " & Err.Number
            VariableInfoToLevel = VariableInfoToLevel & ": " & Err.Description
            Err.Clear
            On Error Goto 0
            Exit Function
        End If
        On Error Goto 0
        
        
        For Each MemberInfo In TypeInfo.Members
            Dim Desc
            Dim printNextLevel : printNextLevel = vbFalse
            Desc = ""
            ' based on .Net System.Runtime.IteropService.ComTypes
            '' FIXME: Call by Value/Reference and settable seems to be switched some
            '' InvokeKind seems to not encode value passing, rather settable/not settable
            '' Needs more work to decode byValue/byReference
            Select Case MemberInfo.InvokeKind
                Case InvokeKindFunction
                    If MemberInfo.ReturnType.VarType <> 24 Then
                        Desc = "  Function " & TypeNameFromVarType(MemberInfo.ReturnType.VarType)
                    Else
                        Desc = "  Sub"
                    End If
                    Desc = Desc & " " & MemberInfo.Name
                    Dim ParameterList
                    ParameterList = Array()
                    Dim Parameter
                    For Each Parameter In MemberInfo.Parameters
                        ReDim Preserve parameterList(UBound(ParameterList) + 1)
                        ParameterList(Ubound(parameterList)) = Parameter.Name
                    Next
                    Desc = Desc & "(" & Join(ParameterList, ", ") & ")"
                    'Set parameters = Nothing
                Case InvokeKindPropertyGet
                    Desc = "  Data Member " & MemberInfo.Name
                    printNextLevel = vbTrue
                Case InvokeKindPropertyPut
                    ' Seems to be 
                    Desc = "  Property " & MemberInfo.Name & " [set by val"
                    If IsGettable(obj, MemberInfo.Name) Then 
                        Desc = Desc & "/get"
                        printNextLevel = vbTrue
                    End If
                    Desc = Desc & "]"
                    'Stop
                Case InvokeKindPropertyPutRef
                    'Stop
                    Desc = "  Property " & MemberInfo.Name & " [set by ref"
                    If IsGettable(obj, MemberInfo.Name) Then 
                        Desc = Desc & "/get"
                        printNextLevel = vbTrue
                    End If
                    Desc = Desc & "]"
                    'Stop
                Case Else
                    Desc = "  Unknown member, InvokeKind " & MemberInfo.InvokeKind
            End Select
            VariableInfoToLevel = VariableInfoToLevel & vbNewLine & _
                                  indent & Desc
            If printNextLevel And level < max_level Then
                VariableInfoToLevel = VariableInfoToLevel & vbNewLine & _
                    VariableInfoToLevel(eval("obj." & MemberInfo.Name), level + 1, max_level)
            End If
        Next
        Set TypeInfo = Nothing
        Set TLI = Nothing
    End If
End Function
Function IsGettable(obj, memberName)
    Dim value
    On Error Resume Next
    Err.Clear
    value = eval("obj." & memberName)
    Stop
    If Err.Number <> 0 And _
       Err.Number <> 438 And _
       Err.Number <> 450 Then
        WScript.Echo Err.Number & ": " & Err.Description
    End If
    
    '438: Object doesn't support this property or method
    '450: Wrong number of arguments or invalid property assignment
    If Err.Number = 438 Or _
       Err.Number = 450 Then
        IsGettable = vbFalse
    Else
        IsGettable = vbTrue
    End If
    
End Function
Function IsSimpleType(obj)
    If (isEmpty(obj) Or isNull(obj)) And (Not IsObject(obj)) And (Not isArray(obj)) Then
        IsSimpleType = vbTrue
    Else
        IsSimpleType = vbFalse
    End If
End Function 
' Decode Type Number to something readable
Function TypeNameFromVarType(typeNr)
    Dim typeDetails
    set typeDetails = CreateObject("Scripting.Dictionary")
    typeDetails.add 0,  "vbEmpty (uninitialized variable)"
    typeDetails.add 1,  "vbNull (value unknown)"
    typeDetails.add 2,  "vbInteger" ' Short?
    typeDetails.add 3,  "vbLong" ' Integer?
    typeDetails.add 4,  "vbSingle"
    typeDetails.add 5,  "vbDouble"
    typeDetails.add 6,  "vbCurrency"
    typeDetails.add 7,  "vbDate"
    typeDetails.add 8,  "vbString"
    typeDetails.add 9,  "vbObject"
    typeDetails.add 10, "Exception"
    typeDetails.add 11, "vbBoolean"
    typeDetails.add 12, "vbVariant"
    typeDetails.add 13, "DataObject"
    typeDetails.add 14, "vbDecimal"
    typeDetails.add 17, "vbByte"
    typeDetails.add 18, "vbChar"
    typeDetails.add 19, "ULong"
    typeDetails.add 20, "Long" ' realy Long?
    typeDetails.add 24, "(void)"
    typeDetails.add 36, "UserDefinedType"
    If typeDetails.Exists(typeNr) Then
        TypeNameFromVarType = typeDetails(typeNr)
    ElseIf typeNr > 8192 Then
        TypeNameFromVarType = "vbArray{" & TypeNameFromVarType(typeNr - 8192) & "}"
    Else
        typeNameFromVarType = "Unknown Type " & typeNr
    End If
End Function
' Some nice example class to demonstrate all possible interfaces.
Class MyClass
    Dim Name_
    Dim Name2_
    Dim Name3_
    Dim Name4_
    Dim dict
    Private Sub Class_Initialize()
        Name_ = "foo"
        Name2_ = "bar"
        Name3_ = "baz"
        Name4_ = "spam"
        Set dict = CreateObject("Scripting.Dictionary")
    End Sub
    
    Private Sub Class_Terminate()
        Set dict = Nothing
    End Sub
        
    Public Property Get Name
        Name = Name_
    End Property
    Public Property Let Name(ByVal Value)
      Name_ = Value
    End Property
    Public Property Let Name2(ByRef Value)
      Set Name2_ = Value
    End Property
    Public Property Get Name3
      Name3 = Name3_
    End Property
    Public Property Set Name3(ByVal Value)
      Set Name3_ = Value
    End Property
    Public Property Get Name4
      Name4 = Name4_
    End Property
    Public Property Set Name4(ByRef Value)
      Set Name4_ = Value
    End Property
    Sub TestSub()
        WScript.Echo "Test"
    End Sub
    Sub TestFunc(message)
        WScript.Echo "Test: " & message
    End Sub
    Sub TestFunc2(ByRef message)
        WScript.Echo "Test: " & message
    End Sub
    Function Add(first, second)
        Add = first + second
    End Function
    Function Substract(ByVal first, ByRef second)
        Add = first - second
    End Function
End Class
Sub testVariableInfo()
    Dim variable
    ' vbEmpty
    Wscript.Echo VariableInfo(variable)
    variable = Null
    Wscript.Echo VariableInfo(variable)
    Set variable = Nothing
    Wscript.Echo VariableInfo(variable)
    Wscript.Echo VariableInfo(Int(23))
    Wscript.Echo VariableInfo(cLng(23))
    Wscript.Echo VariableInfo(2147483647)
    Wscript.Echo VariableInfo(5/4)
    Wscript.Echo VariableInfo(4 * Atn(1)) ' Simplest way to pi, not all inverse functions like arcsin are defined.
    Wscript.Echo VariableInfo(3.4E38)
    Wscript.Echo VariableInfo(CDbl(3.4E38))
    Wscript.Echo VariableInfo(cCur(20.123456))
    Wscript.Echo VariableInfo(now)
    Wscript.Echo VariableInfo("Some Text")
    Wscript.Echo VariableInfo(Err)
    
    Dim MyObject
    Set MyObject = new MyClass
    Wscript.Echo VariableInfo(MyObject)
    Set MyObject = Nothing
    Dim TestAEmpty()
    Wscript.Echo VariableInfo(TestAEmpty)
    ReDim TestA1(17)
    Wscript.Echo VariableInfo(TestA1)
    Dim TestA2(3, 7)
    Wscript.Echo VariableInfo(TestA2)
   
    Dim TestA3
    TestA3 = Array(4, 5, 6)
    Wscript.Echo VariableInfo(TestA3)
    Dim dict
    Set dict = CreateObject("Scripting.Dictionary")
    WScript.Echo VariableInfo(dict)
    Set dict = Nothing
End Sub
testVariableInfo

有关Typelib接口的更多信息,请从Microsoft KB文章224331中获取文档帮助文件

Matthew Curland在他的书《Advanced Visual Basic 6》的网站上提供了一个不错的程序Type Library Editor (EditTLBEval.exe)作为评估版本,以及相应的文档

特别是在这种情况下,我真的很喜欢这一行,如果你是一个拒绝承认VB普遍接受的局限性的Visual Basic开发人员,这本书绝对适合你。作者:Ted patinson。

VBWebProfi给出了TLI的提示,谢谢。计算细节和编写代码是几个小时的工作,虽然;-)

VBScript本身不支持TypeNameVarType函数之外的类型自省,它会给你一个对象的类型,但不会给你访问它的内部结构。

正如其他答案所解释的那样,有一个DLL可以提供这个功能,但它没有随Windows一起发布,而且由于它是旧版本Visual Studio的一部分,现在可能没有合法的方式获得它。

虽然部分正确,但它是不完整的....Google, GetObjectText_, Methods_, &Propeties_

引用的方法只对通过WbemScripting连接到远程主机的cimv2名称空间时收集的对象有效。SWbemLocator对象。如果这个对象有能力在本地主机上工作,对我来说是不明显的。

一旦你这样做了,你可以查询其中包含的任何类[Win32_Services,Win32_Drives等],并在对象上使用For-Next循环查询结果集中的对象,如下所示…

For Each oProp in oObject.Properties_
    'be careful here because some propeties may be an object or an array.
    'so test for that here using "typename" or "vartype"
    wScript.Echo oProp.Name & vbTab & oProp
Next

还是……

For Each oMethod in oObject.Methods_
    wScript.Echo oProp.Name
Next

最后,……

For Each oProp in oObject.Properties_
   'This will display all of an objects properties
   oProp.GetObjectText_
Next

如果您恰好使用HP UFT或QTP,那么请遵循以下步骤:

1)在笔记本电脑上安装任何版本的MS Visual Studio。(不用担心授权,你不会运行VS)

2)重新启动计算机。

3)启动UFT或QTP,加载脚本并按F11,(或暂停在您想要检查的对象附近的任何代码段)。

4)将对象添加到Watch窗口。它可以是Object Repository对象或编程描述。

如果对象存在,该对象现在将在监视窗口中显示两个加号(+),可以展开以显示所有可用的方法和属性,以及可以展开的子对象。

使用TLI。TLI.TLIApplication类(来自tlbinf32.dll)可以从它们的实例中检查各种COM对象。探索Excel或其他微软产品中的TLI库,这些产品支持脚本,并具有能够添加引用的脚本编辑器,然后添加tlbinf32.dll。引用中的名称为"Typelib information"。

请注意,DLL并没有随Windows一起发布。

使用InterfaceInfoFromObject()方法VBScript类,或者尝试ClassInfoFromObject()

Option Explicit
Dim TLI
Dim MyObject
Dim TypeInfo
Dim MemberInfo
Set TLI = CreateObject("TLI.TLIApplication")
Set MyObject = New MyClass
Set TypeInfo = TLI.InterfaceInfoFromObject(MyObject)
For Each MemberInfo In TypeInfo.Members
    WScript.Echo MemberInfo.Name
Next
Class MyClass
    Dim Name_
    Public Property Get Name
        Name = Name_
    End Property
    Public Property Let Name(ByVal Value)
        Name_ = Value
    End Property
End Class

试试这个…

For i = 0 To webElementCount-1 Step 1
  innertextProp = myValue2(i).GetROProperty("innertext")
  print i & innertextProp
  print innertextProp
Next

相关内容

  • 没有找到相关文章

最新更新