Is there any way to list available methods for created object in VBS?
For example:
Set IE = CreateObject("InternetExplorer.Application")
I want to list available properties of this object, as:
IE.AddressBar IE.Application IE.Busy ...
or methods:
IE.ClientToWindow IE.ExecWB IE.GetProperty ...
How can I discover available properties to arbitrary valid object in VBS?
An object is a collection of properties, and a property is an association between a name (or key) and a value. A property's value can be a function, in which case the property is known as a method. In addition to objects that are predefined in the browser, you can define your own objects.
a method is an action which an object is able to perform. sending a message to an object means asking the object to execute or invoke one of its methods.
The basic properties of an object are those items identified by its four-part name (name, type, instance, and version) and also include owner, status, platform, and release.
To get all own properties of an object in JavaScript, you can use the Object. getOwnPropertyNames() method. This method returns an array containing all the names of the enumerable and non-enumerable own properties found directly on the object passed in as an argument. The Object.
Using a method causes something to happen to an object, while using a property returns information about the object or causes a quality about the object to change. Most objects are returned by returning a single object from the collection.
A property is an attribute of an object or an aspect of its behavior. For example, properties of a document include its name, its content, and its save status, and whether change tracking is turned on. To change the characteristics of an object, you change the values of its properties. To set the value of a property,...
Use Get-Member to see an object’s properties and methods. The Get-Member cmdlet is used to definitively show us a PowerShell object’s defined properties and methods. We use it by piping the output from our Get-Service cmdlet into Get-Member.
What are Methods? Methods are the actions that can be performed by an an Objects or on an Object. In the above Hose example, paintaing is a Method, building a new room is a method. Similarly, if you want to select a range, you need Select method.
Using TypeLib Information Objects
from tlbinf32.dll
it is possible to list all members of a class.
The following script demonstrates the included function VariableInfo
which will return a string with the type of the passed variable, and in case of an Object, all members with details, including type of Property
, callable type (Sub
or Function
), and parameter names and return type in case of Function. The type name of the object in case of a COM
object would be the name of the implemented Interface. Not sure if it works for multiple implemented interfaces, but AFAIK it's not possible to implement multiple interfaces in one class via COM
anyway.
It does not support recursion in any way, because this would lead to infinity loops for some types.
This will give you virtually full working reflection in VBS. Great to explore APIs for example with the 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
For for more information about the Typelib Interface, get the documentation help file from Microsoft KB artivle 224331
Matthew Curland offers for download at the website to his book Advanced Visual Basic 6 the nice program Type Library Editor (EditTLBEval.exe) as evaluation version, and the according Documentation
Especially in this context I really like the line If you're a Visual Basic developer who refuses to recognize the commonly accepted limitations of VB, this book is definitely for you. by Ted Pattison. Just replace VB by VBScript here.
VBWebProfi gave the hint for TLI, thanks for that. Working out the details and writing the code was several hours of work, though ;-)
VBScript itself does not support type introspection outside the TypeName
and VarType
functions, which will give you the type of an object, but won't give you access to its internal structure.
As other answers explained there is a DLL that would provide this feature, but it doesn't ship with Windows, and since it was part of an old version of Visual Studio there might not be a legal way to obtain it nowadays.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With