how to determine at runtime which function to call in vbscript - vbscript

The range of input values possible is quite huge in my case. So a select-case methodology will not work.
So based on my input say flowers.. doffodil,lily,rose,etc, my function name to call would be flowerdoffodil(), flowerlily(), flowerrose(), etc. Ech of these functions are already defined.
Only which one to call will need to be determined at runtime based on my input.
Is there a way to do this in vb script?
Note: I am a rookie programmer and am using QTP for automation.

Use GetRef() as in:
Option Explicit
Function flowerdoffodil()
flowerdoffodil = "my name is daffodil!"
End Function
Function flowerlily()
flowerlily = "my name is lily!"
End Function
Function flowerrose()
flowerrose = "my name is rose!"
End Function
Dim aInp : aInp = Split("doffodil lily rose")
Dim sFnc
For Each sFnc In aInp
Dim fncX : Set fncX = GetRef("flower" & sFnc)
Dim sRes : sRes = fncX()
WScript.Echo sFnc, TypeName(fncX), sRes
Next
output:
cscript 30161364.vbs
doffodil Object my name is daffodil!
lily Object my name is lily!
rose Object my name is rose!
Further food for thought: You can use a Dictionary:
Dim dicFncs : Set dicFncs = CreateObject("Scripting.Dictionary")
Set dicFncs("doffodil") = GetRef("flowerdoffodil")
Set dicFncs("lily") = GetRef("flowerlily")
Set dicFncs("rose") = GetRef("flowerrose")
and call the function(s) like:
Dim sRes : sRes = dicFncs(sFnc)()
(See also: 1, 2, 3)

Related

Use VBScript to VLOOKUP values, or evaluate formula?

For processing orders we're using VBScripts to import them into accounting software. There are several suppliers, each with their own file format, mostly CSV and XML. The first step is to extract all the order lines (custom function per supplier), do some additional processing and then write it to the database, which is the same for all suppliers.
One new supplier uses Excel files with all the order lines in one sheet, except for the corresponding VAT percentage value which are available in another sheet. The VAT percentage per item can be looked up using the itemcode from the order sheet.
The company only has LibreOffice Calc and I understand you could do something like this in macro. However, it is a fully automated process and every other file is already handled by VBScript so I'd rather not make an exception or handle just this one order type manually (opening Calc and running the macro). So it has to be VBS and LibreOffice in this case.
Here is the VBScript code I have so far:
Option Explicit
' variables
Dim oSM, oDesk
Dim sFilename
Dim oDoc
Dim oSheet
Dim iLine
Dim sCode, iCount, sDesc, fCost, Perc
Set oSM = WScript.CreateObject("com.sun.star.ServiceManager")
Set oDesk = oSM.createInstance("com.sun.star.frame.Desktop")
sFilename = "file:///C:/orders/import/supplier_orderlist_08-01-2019.xls"
set oDoc = oDesk.loadComponentFromURL( sFilename, "_blank", 0, Array() )
set oSheet = oDoc.getSheets().getByName("Orderlist")
For iLine = 11 to 12 ' testing first 2 lines
sCode = oSheet.getCellByPosition(1, iLine).getString()
iCount = oSheet.getCellByPosition(2, iLine).getString()
sDesc = oSheet.getCellByPosition(5, iLine).getString()
fCost = oSheet.getCellByPosition(8, iLine).getString()
'lookup doesn't work
Perc = Macro_VLOOKUP(sCode, oDoc)
WScript.Echo sCode & " - " & iCount & "x - " & sDesc & " => " & fCost & ", " & Perc & "%"
Next 'iLine
WScript.Quit 1
Function Macro_VLOOKUP(SearchValue, oDocGlob)
Dim oSheetLook, CellRange
Dim Column, Mode, svc, arg, Value
Set oSheetLook = oDocGlob.getSheets().getByName("Itemlisttotal")
Set CellRange = oSheetLook.getCellRangeByName("A1:B10000")
Column = 1
Mode = 0
svc = createUnoService("com.sun.star.sheet.FunctionAccess") '<- error: variable not defined
arg = Array(SearchValue, CellRange, Column, Mode)
Value = svc.callFunction("VLOOKUP", arg)
Macro_VLOOKUP = Value
End Function
It gives an error on the line with createUnoService:
Variable not defined 'createUnoService'
which is probably a LibreOffice Basic function and needs to be translated to the VBScript equivalent. There isn't much documentation or examples on this, so I can only guess, but Set svc = WScript.CreateObject("com.sun.star.sheet.FunctionAccess") also doesn't work and gives a "class name not found" error.
Is it possible to do a VLOOKUP (or something similar) from VBScript in LibreOffice Calc?
Or is there a way to evaluate a cell formula from a string at runtime?

How to delete excel sheet from UFT

I am trying to write a function which will delete all sheets except the one passed as parameter. Below function is being called but function does not delete any sheets. How can I delete all worksheets except one?
........
Set ExcelObj = createobject("excel.application")
ExcelObj.Visible = true
Set ConfigFile = ExcelObj.Workbooks.Open (FilePath)
Set ConfigSheet = ConfigFile.Worksheets("Scripts")
Set ConfigApplicationSheet = ConfigFile.Worksheets("Applications")
Set ExecutiveSummarySheet = ConfigFile.Worksheets("Summary")
ExcelObj.ActiveWorkBook.SaveAs SummaryFilePath
DeleteSheet "ConfigScripSheet","Summary"
Function DeleteSheet(ConfigSheet,mySheetname)
'Writing Name and Path of each File to Output File
For Each ObjFile In ObjFiles
ObjOutFile.WriteLine(ObjFile.Name & String(50 - Len(ObjFile.Name), " ") & ObjFile.Path)
Next
ObjOutFile.Close
DeleteSheet = 0
ExcelObj.DisplayAlerts = False
For Each objWorksheet In ConfigSheet.Worksheets
If not objWorksheet.Name = mySheetname Then
DeleteSheet = 1
ConfigScripSheet.sheets(objWorksheet.Name).Select
ConfigScripSheet.sheets(objWorksheet.Name).Delete
ExcelObj.DisplayAlerts = False
End If
Next
End Function
Trying to correct your code above was too much of a minefield for me as I couldn't tell what you meant in several places - so I rewrote it based on what you had said in the description was your goal.
The code below will open the file, associate the objects the way you had them, pass the workbook object and a sheet name not to be deleted into the DeleteSheet function, which will delete any sheet in the workbook that is not named as per the passed in parameter SheetNameNotToDelete
Let me know if any of the code is unclear.
Option Explicit ' Forces declaration of variables
Dim FilePath, SummaryFilePath '<-- Need set to some value!
FilePath = ""
SummaryFilePath = ""
Dim ExcelObj : Set ExcelObj = CreateObject("Excel.Application")
Dim ConfigFile : Set ConfigFile = ExcelObj.Workbooks.Open(FilePath)
Dim ConfigSheet : Set ConfigSheet = ConfigFile.Worksheets("Scripts")
Dim ConfigApplicationSheet : Set ConfigApplicationSheet = ConfigFile.Worksheets("Applications")
Dim ExecutiveSummarySheet : Set ExecutiveSummarySheet = ConfigFile.Worksheets("Summary")
ExcelObj.ThisWorkbook.SaveAs SummaryFilePath
DeleteSheet ConfigFile, "Summary"
Function DeleteSheet(ByRef WorkbookObj, ByVal SheetNameNotToDelete)
Dim oWorksheet
For Each oWorksheet In WorkbookObj.Worksheets
If oWorksheet.Name <> SheetNameNotToDelete And WorkbookObj.Worksheets.Count >=2 Then
oWorksheet.Delete ' Excel won't let you delete all worksheets from a workbook
End If ' the check on Count >=2 covers the case where no worksheet exists
Next ' called "Summary" to be left
End Function

To convert string to double in UFT/QTP

I am trying to convert string to double in UFT but It shows the output without decimal point. below is the code for reference.
vStr = "1000000.589765"
msgbox Typename(vStr)
strV1=CDBL(formatNumber(vStr,4))
msgbox Typename(strV1)
print strV1
Output: 1000000589765
Note that without formatNumber, its not working.
Yet another implementation using DotNetFactory. Just an another thought. I am not denying to use CDbl. But worth to give a shot.
'Test Code
Dim strConvertedCode
strConvertedCode = ConvertDataType("1000000.589765","Double")
If strConvertedCode <> null Then
Msgbox strConvertedCode
End If
Public Function ConvertDataType(ByVal SourceData,ByVal ConversionDataType)
'Initialization of variables
Dim objDotNetFactory
Dim strConvertedData : strConvertedData = null
Dim strSystemNamespace
'Determine the destination data type
Select Case UCase(ConversionDataType)
Case "DOUBLE"
strSystemNamespace = "System.Double"
'Implement further for your data types
'Reference https://msdn.microsoft.com/en-us/library/ms228360(v=vs.90).aspx
Case Default
Set objDotNetFactory = DotNetFactory.CreateInstance("System.Int32")
End Select
Set objDotNetFactory = DotNetFactory.CreateInstance(strSystemNamespace)
'Check the dot net factory instance is successful
If Not IsObject(objDotNetFactory) Then
Reporter.ReportEvent micWarning,"Data type convertor","Conversion from String to " & ConversionDataType & " failed, Since DotNetFactory instance was not created."
ConvertDataType = strConvertedData
Exit Function
End If
strConvertedData = objDotNetFactory.Parse(SourceData)
ConvertDataType = strConvertedData
End Function

vbs execute another vbs script with dictionary as parameter

i am trying to execute a vbscript from another vbscript. The think is, i have to pass a dictionary as parameter, but i always get the same error message.
Here is my code so far:
dim objShell
Set objShell = Wscript.CreateObject("WScript.Shell")
dim dicExp
Set dicExp = CreateObject("Scripting.Dictionary")
dic.add 0, 10
objShell.Run "C:\Users\groeschm\Desktop\ODBCAktuell.vbs " & dicString
But i always get this error message:
Error 800A01C2 - Wrong number of arguments of invalid property assignment.
Greetings,
Michael
You cannot pass an object reference to WScript.Shell.Run. See http://msdn.microsoft.com/en-us/library/d5fk67ky(v=vs.84).aspx, it says the command line argument is a string, and nothing else.
You cannot pass a Scripting.Dictionary reference, nor can you encode that reference into the string argument.
It´s as simple as that!
And even if you could, this would be useless because the called VBS does not share the same global scope as the caller code.
You should consider alternatives to Run. You could put the ODBCAktuell.vbs code into a function, and call that instead. Or you consider ExecuteFile or one of the related intrinsics.
(Without knowing what ODBCAktuell.vbs contains, and without knowing what exactly you are trying to accomplish, it is difficult to advise you further than that.)
There is a similar question based on the same brainbug: Create instance for a class(resides in B.vbs) from another .VBS file
The OT's code is messed up. dicString is undefined. It does not throw the error claimed, but an "Object Required", because the dictionary is named dicExp, not dic.
While TheBlastOne is right to state that you can't pass anything except strings via the command line, the wish to communicate other (more complex) types of data is legitimate. Making numbers or dates from command line args is standard procedure. And: wanting to re-use code via some kind of import/using/include mechanism isn't a brainbug but essential for good programming.
A general approach to serialisation (via strings) is JSON, but it's not easy to use it in VBScript (cf).
The starting point(s) for a 'roll your own' approach for simple cases (dictionaries with numbers/scalars/simple strings as keys and values) is trivial:
Stringify:
cscript passdic.vbs
cscript recdic.vbs "1 2 3 4"
1 => 2
3 => 4
passdic.vbs:
Option Explicit
Function d2s(d)
ReDim a(2 * d.Count - 1)
Dim i : i = 0
Dim k
For Each k In d.Keys()
a(i) = k
i = i + 1
a(i) = d(k)
i = i + 1
Next
d2s = Join(a)
End Function
Function qq(s)
qq = """" & s & """"
End Function
Dim d : Set d = CreateObject("Scripting.Dictionary")
d(1) = 2
d(3) = 4
Dim c : c = "cscript recdic.vbs " & qq(d2s(d))
WScript.Echo c
Dim p : Set p = CreateObject("WScript.Shell").Exec(c)
WScript.Echo p.Stdout.ReadAll()
recdic.vbs:
Option Explicit
Function s2d(s)
Set s2d = CreateObject("Scripting.Dictionary")
Dim a : a = Split(s)
Dim i
For i = 0 To UBound(a) Step 2
s2d.Add a(i), a(i + 1)
Next
End Function
Dim d : Set d = s2d(WScript.Arguments(0))
Dim k
For Each k In d.Keys()
WScript.Echo k, "=>", d(k)
Next
Code re-use:
cscript passdic2.vbs
cscript recdic2.vbs
1 => 2
3 => 4
passdic2.vbs
Option Explicit
Function d2s(d)
ReDim a(d.Count - 1)
Dim i : i = 0
Dim k
For Each k In d.Keys()
a(i) = "cd.Add " & k & "," & d(k)
i = i + 1
Next
d2s = "Function cd():Set cd=CreateObject(""Scripting.Dictionary""):" & Join(a, ":") & ":End Function"
End Function
Dim d : Set d = CreateObject("Scripting.Dictionary")
d(1) = 2
d(3) = 4
CreateObject("Scripting.FileSystemObject").CreateTextFile("thedic.inc").Write d2s(d)
Dim c : c = "cscript recdic2.vbs"
WScript.Echo c
Dim p : Set p = CreateObject("WScript.Shell").Exec(c)
WScript.Echo p.Stdout.ReadAll()
thedic.inc
Function cd():Set cd=CreateObject("Scripting.Dictionary"):cd.Add 1,2:cd.Add 3,4:End Function
recdic2.vbs
Option Explicit
ExecuteGlobal CreateObject("Scripting.FileSystemObject").OpenTextFile("thedic.inc").ReadAll()
Dim d : Set d = cd()
Dim k
For Each k In d.Keys()
WScript.Echo k, "=>", d(k)
Next

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