Overriding CreateObject Function in VBScript - vbscript

I want to override the default CreateObject() function in VBScript with my own.
Basically this example in VB6:
http://www.darinhiggins.com/the-vb6-createobject-function/
I cannot figure out is this line:
Set CreateObject = VBA.CreateObject(Class$, ServerName$)
How do I refer to "VBA" in VBSript?

This quick test seems to work...
Function CreateObject(className, serverName)
'---- override the CreateObject
' function in order to register what
' object is being created in any error message
' that's generated
Dim source, descr, errNum
WScript.echo "In custom CreateObject"
If Len(serverName) > 0 Then
Set CreateObject = WScript.CreateObject(className, serverName)
Else
Set CreateObject = WScript.CreateObject(className)
End If
End Function
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject", "")
path = fso.GetAbsolutePathName(".")
WScript.echo path
No guarantees! ;-)

I don't think you can override it so that all code will use it, only YOUR code.
In which case, it doesn't matter what it's called (unless you have tons of existing code you can't change). Can you call it CreateObjectEx() or ExCreateObject() or something like that? Have this function add all your error handling and such and then turn around and call the main/core CreateObject() method

Related

Quitting the IE in the end of VBA function

I implemented several functions which relies on downloading some information from some websites.
The simplest example of such a function is:
Public Function getSomething(webAddress As String)
Dim html As HTMLObjectElement
Set html = getWebContents(webAddress)
Set elems = html.body.getElementsByTagName(tagName)
...
End Function
The function for acquire data from websites is:
Public Function getWebContents(webAddress As String) As HTMLObjectElement
Dim ie As InternetExplorer
Dim html As HTMLDocument
Set ie = New InternetExplorer
ie.Visible = False
ie.Navigate webAddress
Do While ie.READYSTATE <> READYSTATE_COMPLETE
Application.StatusBar = "Trying ..."
DoEvents
Loop
Set getWebContents = ie.Document
'close down IE and reset status bar
'ie.Quit
Set ie = Nothing
Application.StatusBar = ""
End Function
The problem is that it seems that I need the line ie.Quit to be uncommented to close the IE instance. But when I uncomment ie.Quit the line
Set elems = html.body.getElementsByTagName(tagName)
generates errors.
It seems that I cannot use HTMLObjectElement returned by function getWebContents when IE has been quitted. How to deal with that? I could implement a try...finally block in getSomething function and open ie there and close in the finally block. However I have many functions of a similar nature and making many similar try...finally blocks seems a stupid idea.
Any thoughts?
Thanks!
You should define a procedure to handle the object lifetime from creation to destruction. You can then pass a reference for the object to the function.
Lastly, you can dispose the object even if an error occurs at any stange.
Public Sub Main()
On Error GoTo ErrProc
Dim ie As InternetExplorer
Set ie = New InternetExplorer
'....
Dim obj As Object
obj = getWebContents(ie, "url")
Leave:
ie.Quit
Set ie = Nothing
Set obj = Nothing
Application.StatusBar = ""
On Error GoTo 0
Exit Sub
ErrProc:
MsgBox Err.Description, vbCritical
Resume Leave
End Sub
Public Function getWebContents(ie As InternetExplorer, webAddress As String) As HTMLObjectElement
'...
End Function
You are keeping a pointer to the DOM in the html variable. If you close IE, you are pointing to something non-existing.
The simple answer is to close IE at the end of getSomething. In your case, this means that you have to restructure your code so that your IE variable is accessible from other places than in getWebContents

How to fix Wscript.CreateObject returning empty when prefix is specified?

I'm trying to process event handlers for ADODB.Command object. When I specify a prefix, Wscript.CreateObject exits the function without issuing any error message. When the prefix is removed from Wscript.CreateObject, the ADODB.Command object is created.
Additionally when setting On Error Resume Next, Wscript.CreateObject returns and empty object.
Can someone please tell me what I'm doing wrong ?
Code:
DIM tsqlcmd
On Error Goto 0
SET tsqlcmd = WScript.CreateObject("ADODB.Command", "ehdlr_tsqlcmd_")
.....
Private Sub ehdlr_tsqlcmd_ExecuteComplete( RecordsAffected, pError, adStatus, pCommand, pRecordset, pConnection)
' place any code you desire here, for example
If adStatus = STATUS_adStatusOK Then
MsgBox( "tsqlcmd_ExecuteComplete Records affected = " & RecordAffected)
Else
MsgBox( "tsqlcmd_ExecuteComplete ExecuteComplete Status = " & adStatus)
End If
End Sub

WScript.GetObject() does not work, but GetObject() does

When using VBScript to get processes list on Windows 7 Pro, this script, named as getobject.vbs, is used:
Dim objWMIService
'
' case 1: this works:
'
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
WScript.Echo "GetObject() worked."
'
' case 2: this does not work:
'
Set objWMIService = WScript.GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
WScript.Echo "WScript.GetObject() does not work. So this line never runs."
'
' ...
'
Set objWMIService = Nothing
In case 1, GetObject() works well.
But in case 2, when WScript.GetObject() is used, this error occurs:
GetObject() is a method of WScript, please see Microsoft ref..
Why cannot one call it by the complete reference in the form of WScript.GetObject()?
As a comparision, the both calls worked:
Dim xobj
Set xobj = CreateObject("Excel.Application")
Set xobj = WScript.CreateObject("Excel.Application")
There is a GetObject function of the VBScript language and a GetObject method of the WScript object. They are not the same, their prototypes and usage/pragmatics differ.
Update wrt comment:
Read Eric Lippert's article to understand why there are host- and language-provided variants of similar functions.
My rule of thump: Use the language version of Create/GetObject(), except when you need the extras (e.g. events) provided by the host application.

Variable scope in VBScript functions

I have a question about variable scope in VBScript. I know there's the following keywords (from autoitscript.com):
Dim = Local scope if the variable name doesn't already exist globally (in which case it reuses the global variable!)
Global = Forces creation of the variable in the Global scope
Local = Forces creation of the variable in the Local/Function scope
Imagine that I have the following .vbs file:
Dim strPath
strPath = "C:\folder"
DisplayPath strPath
Sub DisplayPath(strPath) 'Does this strPath get it's own local scope?
MsgBox strPath
End Sub
In the function: DisplayPath(strPath), is strPath a local variable? Or do functions/subs have access to the strPath defined at the top of the main section of the script as a global variable?
Also, what's the point of explicitly using Dim versus just defining variables as I use them, which is possible in scripting languages?
The strPath in the DisplayPath procedure will be a new variable but not for the reasons you expect, there is subtle problem with your code that will cloud the issue.
When calling Sub procedure the VBScript syntax does not include parentheses. For example:-
Sub MyProc(Param1, Param2)
'' # Do stuff
End Sub
MyProc("Hello", "World")
the above would result in a syntax error. It should be called:-
MyProc "Hello", "World"
Now when there is only one parameter a syntax error does not occur. This is because another use of parentheses is as part of an expression e.g. '(a + b) * c'. In the case of:-
DisplayPath(strPath)
VBScript resolves the "expression" (strPath) and pass the result to DisplayPath. Its this result that gives rise to new storage hold the result the expression.
Had you called with
DisplayPath strPath
no new created.
However what about this:-
Sub DisplayPath(something)
MsgBox something
End Sub
There is still no new storage allocated. something will point at the same memory that strPath does.
Edit
The code below works:-
Dim strPath
strPath = "c:\folder"
Display
Sub Display()
MsgBox strPath
End Sub
The declaration of strPath outside of a procedure causes it to have global scope.
As to the point of using explicit Dim what would happen if the assignment line above looked like this?
strPath = "c:\folder"
A new variable called strPath would come into existence and strPath would remain empty. You should always begin your VBScript files with the line:-
Option Explicit
This will force you to explicitly Dim all variables to be used and will save you hours of debugging time.

VBScript: How to utiliize a dictionary object returned from a function?

I'm trying to return a dictionary from a function. I believe the function is working correctly, but I'm not sure how to utilize the returned dictionary.
Here is the relevant part of my function:
Function GetSomeStuff()
'
' Get a recordset...
'
Dim stuff
Set stuff = CreateObject("Scripting.Dictionary")
rs.MoveFirst
Do Until rs.EOF
stuff.Add rs.Fields("FieldA").Value, rs.Fields("FieldB").Value
rs.MoveNext
Loop
GetSomeStuff = stuff
End Function
How do I call this function and use the returned dictionary?
EDIT: I've tried this:
Dim someStuff
someStuff = GetSomeStuff
and
Dim someStuff
Set someStuff = GetSomeStuff
When I try to access someStuff, I get an error:
Microsoft VBScript runtime error: Object required: 'GetSomeStuff'
EDIT 2: Trying this in the function:
Set GetSomeStuff = stuff
Results in this error:
Microsoft VBScript runtime error: Wrong number of arguments or invalid property assignment.
I wasn't too sure of what was your problem, so I experimented a bit.
It appears that you just missed that to assign a reference to an object, you have to use set, even for a return value:
Function GetSomeStuff
Dim stuff
Set stuff = CreateObject("Scripting.Dictionary")
stuff.Add "A", "Anaconda"
stuff.Add "B", "Boa"
stuff.Add "C", "Cobra"
Set GetSomeStuff = stuff
End Function
Set d = GetSomeStuff
Wscript.Echo d.Item("A")
Wscript.Echo d.Exists("B")
items = d.Items
For i = 0 To UBound(items)
Wscript.Echo items(i)
Next
Have you tried doing
set GetSomeStuff = stuff
in the last line of the function?
Have you tried:
Dim returnedStuff
Set returnedStuff = GetSomeStuff()
Then "For Each" iterating over the dictionary? There's an example of using the Dictionary (albeit for VB6, the gist of it is the same though!) here.

Resources