I'm trying to make a VBScript to open or get a handle of an already opened Excel workbook, and run a macro which executes a series of SQL queries against the workbook itself, using worksheets as tables. This workbook is expected to stay open by some users. The workbook act as an semi-automated report delivery vessel, which updates itself with a certain action taken in the ERP system the users use.
Problem
The scripts work fine independently but the ADO call in VBA macro fails the first time it's called if the workbook was opened by the script, returning a run-time error No value given for one or more required parameters. But running the same macro with the same parameter again, whether from the VBScript or VBA, succeeds. And if the file has already been opened manually then the macro succeeds every time. Below summarizes the scenarios.
Excel instance exists and the desired workbook has already been opened by hand (File double clicked or through Excel GUI File->Open) - Get a handle with GetObject and run macro => succeeds every time
Excel instance exists but the desired workbook isn't open - Open the book using the existing app handle then run macro => the macro errors the first run. Succeeds on subsequent runs
Excel instance does not exist - Create app/workbook objects, open the workbook then run macro => the macro errors the first run. Succeeds on subsequent runs
Some Considerations
- In all scenarios above,
cn.Status = 1at the time of error. - SQL statement that doesn't use JOIN can succeed on the first run. All statements with JOIN fail on the first run.
Processes
- VBS is triggered when a user enters a key value in a certain ERP task
- VBS sends the key value to the workbook as a parameter for macro
- Macro does the following in the order listed order
- Execute RefreshAll to update tables with saved connections
- Execute queries against worksheets using the parameter <--this is where it fails only on the first run.
- Produce properly formatted report
What am I missing in making these codes work?
Macro:VBA
Option Explicit
Public cn as ADODB.Connection
Dim rs As ADODB.Recordset
Dim sSQL as string
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
With cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties = 'Excel 12.0 xml;HDR=YES'"
.CursorLocation = adUseClient
.Open
End With
sSQL = "SELECT t1.column1, t2.column1 FROM t1 INNER JOIN t2 ON t1.pk = t2.pk"
rs.Open strSQL, cn, adOpenStatic, adLockReadOnly
'cn.Execute (strSQL) <--- same results as using RecordSet
FileOpener: VBS
Dim oExcel, oWb
Dim blFileOpen : blFileOpen = False
Set oExcel = GetObject(, "Excel.Application") ' Check if Excel is running
Select Case IsEmpty(oExcel)
Case True 'no Excel instance. Start app and open book
Set oExcel = CreateObject("Excel.Appliation")
Set oWb = oExcel.Workbooks.Open(sPath & sFileName)
Case False 'Excel instance exists. check what's open
For Each wb In oExcel.Workbooks
If oWb.Name = sFileName Then 'File is already open. Get a handle
Set oWB = GetObject(sPath & sFileName)
blFileOpen = True
Exit Sub
End if
Next
'Excel instance exists but the target file wasn't open. Open the file.
Set oWB = oExcel.Workbooks.Open(sPath & sFileName)
End Select
oWB.Application.Visible = True
oWB.Application.Run "Macro", "Param"
