Integrating VBA inside VBScript file - vba

I have a working VBScript file and VBA macro inside Excel worksheet that does this:
Refreshes all data connections
Writes a timestamp in a specific cell
Save and closs the Excel worksheet
VBS file:
Set objExcel = CreateObject("Excel.Application")
objExcel.Application.Run "'G:\Blank.xlsm'!Module9.Date"
objExcel.DisplayAlerts = False
objExcel.Application.Quit
Set objExcel = Nothing
VBA inside the Blank.xlsm worksheet:
Sub Date()
ActiveWorkbook.RefreshAll
With Range("M12")
.Value = Now()
.NumberFormat = "dd/mm/yy hh:mm"
ActiveWorkbook.Save
End With
End Sub
Is it possible to keep the Excel macro-free .xslx file and run both of those functions from a VBScript file, which would not call the macro inside the Excel workbook to do the things I need, but rather complete those tasks by itself? I'm very new to VBScript (and frankly, VBA, too), so I'm sorry if this comes as too basic of a question.

Yes, of course, it's possible. Here:
Option Explicit
Dim objExcel, objWorkBook
Set objExcel = CreateObject("Excel.Application")
Set objWorkBook = objExcel.Workbooks.Open(filePath)
objExcel.Application.Visible = False
objExcel.DisplayAlerts = False
objWorkBook.RefreshAll
With objWorkBook.Sheets(1).Range("M12")
.Value = Now()
.NumberFormat = "dd/mm/yy hh:mm"
End With
objWorkBook.Save
objWorkBook.Close
objExcel.Application.Quit
WScript.Echo "Finished."
WScript.Quit

Related

can excel vba function open a file?

i'm defining a function to save files as .xls format:
Public Function save_as_xls(full_file_path As String) As String
save_as_xls = ""
Dim src_file As Workbook
Set src_file = Workbooks.Open(full_file_path)
src_file.SaveAs filename:=full_file_path, FileFormat:=xlExcel8
src_file.Close
save_as_xls = "OK"
End Function
then call it in excel cell formula as =save_as_xls("c:\temp\test.xls")
However, it doesn't work, the src_file get Nothing from Workbooks.Open
Is there a limitation on vba functions that cannot open files? I only know that it can't write to other cells.
Excel UDF have certain limitations, so you can't save workbook. You may try a workaround with late bound instance of Excel as shown in the below code.
Put this code to the standard module:
Public objExcel As Application
Public Function SaveAsXls(FilePath As String) As String
If objExcel Is Nothing Then
Set objExcel = CreateObject("Excel.Application")
With objExcel
.Visible = True ' for debug
.DisplayAlerts = False
End With
End If
With objExcel
With .Workbooks.Open(FilePath)
.SaveAs _
Filename:=FilePath, _
FileFormat:=xlExcel8
.Close True
End With
End With
SaveAsXls = "OK"
End Function
Put this code to ThisWorkbook section:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If TypeName(objExcel) = "Application" Then objExcel.Quit
End Sub
So you can call it in Excel cell formula as =SaveAsXls("c:\temp\test.xls")

Workbooks.open return before focus (Excel 2010 and 2016)

I have a macro that opens a new Workbook and then activate (focus) to first Workbook.
Code:
Set mainWorkbook = ActiveWorkbook
Set bdWorkbook = Workbooks.Open(FileName:="Another.xlsm", ReadOnly:=True)
mainWorkbook.Activate
I've got this code working in Excel 2007, but I've encountered an issue with the open workbook in Excel 2010 and later. The problem happens because Workbooks.Open returns to VBA before Excel Activate the new workbook [it works fine using debugger].
I can make an workarround using a Application.Wait (Now + TimeValue("0:00:01")), but......
EDIT: My code that dosen't work in Excel 2016
Sub Sample()
Dim path As String
path = "A_PATH_FROM_MY_SERVER"
actualScreenUpdate = Application.ScreenUpdating
Application.ScreenUpdating = False
Set MainWB = ActiveWorkbook
Workbooks.Open fileName:=path, UpdateLinks:=False, ReadOnly:=isReadOnly
Set bdWB = ActiveWorkbook
DoEvents
MainWB.Activate
Application.ScreenUpdating = actualScreenUpdate
With Sheets(MY_BD_SHEET)
bdWB.ActiveSheet.UsedRange.Copy .[A1]
'....
End With
End Sub
Is this what you want? (Tried And Tested)
This will open the relevant workbook and minimize it thereby returning focus to your main workbook.
Sub Sample()
Dim wbThis As Workbook, wbThat As Workbook
Set wbThis = ThisWorkbook
Set wbThat = Workbooks.Open("C:\Users\Siddharth\Desktop\Sample.xlsx")
DoEvents
Application.WindowState = xlMinimized
' OR
ActiveWindow.WindowState = xlMinimized
End Sub
EDIT
After seeing your current Edit.
MainWB.Activate
Application.ScreenUpdating = actualScreenUpdate
You are activating when the ScreenUpdating = False? Set it to True and then Activate it :)

Can't close Excel App with vba in a scheduled task

I have made a code in vba which works with different Workbooks and Worksheets. This code must be execute in a scheduled task. But for an unknow reason I have a problem with it :
When I execute it manually, it works fine and excel closes itself. But with my scheduled task, Excel closes all Workbooks and Worksheets but it stays open.
Here you have my code :
Set xlApp = GetObject(, "excel.application")
Set wkbMe = xlApp.ActiveWorkbook
test = False
xlApp.DisplayAlerts = False
xlApp.AskToUpdateLinks = False
'Open files
xlApp.Workbooks.Open Filename:=MarketDataPath & WbRiskedge, ReadOnly:=True
xlApp.Workbooks.Open Filename:=MarketDataPath & WbMarketData, ReadOnly:=True
Set WorksheetIncoming = xlApp.Workbooks(WbMarketData).Worksheets(wsIncoming)
Set WorksheetMarketdata = xlApp.Workbooks(WbMarketData).Worksheets(WsMarketData)
xlApp.Workbooks.Open Filename:=GTPath & WbGoodTime, ReadOnly:=True
Cells.Copy
WorksheetIncoming.Activate
Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Workbooks(WbGoodTime).Close
WorksheetMarketdata.Calculate
Worksheets(wsMarketDataForWebsite).Calculate
Worksheets(wsMarketDataForWebsite).Activate
If test = False Then
Application.Run "MarketEnv.xlsm!subCreateCSV"
End If
Workbooks(WbMarketData).Close , False
Workbooks(WbRiskedge).Close , False
xlApp.DisplayAlerts = True
xlApp.AskToUpdateLinks = True
ThisWorkbook.Save
ThisWorkbook.Saved = True
xlApp.Quit
End Sub
I have tried different solutions found on the web but nothing work. Even if I only make :
Set xlApp = GetObject(, "excel.application")
xlApp.Quit
End Sub
my excel stays open.
Anyone can help me plz ?
Okay, this seems long winded... but here goes.
The problem you are seeing is because there can be more than one instance of the Excel Application on a machine at a given time.
When you are manually running the file, you are likely using the default behavior, which is that when you open a workbook directly it opens in your already loaded Excel Application.
This means that when you use:
Set xlApp = GetObject(, "excel.application")
It is actually returning the current Excel.Application.
However, when you load it via the scheduled task, it generates a new Excel.Application in order to handle your task. When it calls the code I quoted it ends up referencing the Excel.Application you already had open (probably).
Since your scheduled workbook is running in a different instance of Excel.Application, when you run xlApp.Quit it only quits that other Excel and not the one actually running the code.
If you want to also close your automated Excel, you will need to add Application.Quit to the end of your sub. Yes, I do mean use both xlApp.Quit AND Application.Quit.
Now technically, you could have more than one Excel Applications open when you load the new one. If you want to close all instances of Excel, the simplest way I know would be to kill all of them via a vbscript call to a program like this which terminates all processes named excel.exe. Note I did not test this on Win 7:
Dim objWMIService, objProcess, colProcess
Dim strComputer, strProcessKill, strFilePath
strComputer = "."
strProcessKill = "'excel.exe'"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")
Set colProcess = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = " & strProcessKill)
For Each objProcess In colProcess
objProcess.Terminate
Next
WScript.Quit
Edit: I just wanted to add that you can replicate the behavior of the scheduled task manually by doing the following:
Have Excel already open.
Navigate through your start menu and open Excel.
From the new instance of Excel, open your workbook.
OR
Have Excel already open.
Run the following Excel.exe [path of workbook in quotes]
Edit 2:
Due to your request, I've written this short vbscript file that will close all open Excel Applications without upsetting auto-recover. If you also want to avoid any, "Do you want to save ..." alerts uncomment the commented section.
On Error Resume Next
Dim xlApp
Set xlApp = GetObject(, "Excel.Application")
Do While Err.Number <> 429
'For each wb in xlApp.Workbooks
' wb.saved = true
'next
xlApp.Quit
Set xlApp = Nothing
Set xlApp = GetObject(, "Excel.Application")
Loop
Wscript.quit
To run it, just include the following at the end of your Excel VBA.
Shell "wscript.exe [path of .vbs file]"
I can see you have opened more than one workbook instances with your excel application. You need to close all workbook instances to get the plain excel application and than quit it.
try this: (pseudo code)
dim xlApp as Excel.Application
dim wBook as Excel.Workbook
dim wSheet as Excel.Worksheet
Set xlApp = new Excel.Application
Set wBook = xlApp.Workbooks.Add(wb_Path)
Set wSheet = wBook.Sheets(1)
wSheet.Range("A1").Value = "Hello this is a test from vbcode"
wbook.close saveChanges:= true
xlApp.quit
Above code will open your workbook. write a custom message on your worksheet
saves the changes and closes. and the xlapp will also be terminated/destroyed.

Macro gets disabled if called using a vb script

I am trying to call my excel macro using vbs. Here is a snippet of my code.
Set objExcel = CreateObject("Excel.Application")
Set objWorkbook = objExcel.Workbooks.Open("C:\Folder\Test_PO.xls")
objExcel.Application.Visible = True
objExcel.Application.Run "C:\Folder\Test_PO.xls!Data_Analysis"
objExcel.ActiveWorkbook.Close
objExcel.Application.Quit
WScript.Echo "Finished."
WScript.Quit
Now the problem here is that i am able to open the file but the macro somehow gets disabled here and shows me 'macro may not be present or may be disabled'. I am sure i am calling correct macro name but as soon as the file is opened the Add-ins tab where i had configured the macro to run from gets dissapeared.This does not open if i open the file manually , i can see the tab and run the macro from the tab itself. Any suggestions how i could overcome this problem and get the macro to run ?
Try this
Dim objExcel, objWorkbook
Set objExcel = CreateObject("Excel.Application")
Set objWorkbook = objExcel.Workbooks.Open("C:\Folder\Test_PO.xls")
objExcel.Visible = True
objExcel.Run "Data_Analysis"
objWorkbook.Close
objExcel.Quit
Set objWorkbook = Nothing
Set objExcel = Nothing
WScript.Echo "Finished."
WScript.Quit
EDIT
If the macro is in a module then the above will help. If the macro is in a sheet say, Sheet1 then replace the line
objExcel.Run "Data_Analysis"
with
objExcel.Run "sheet1.Data_Analysis"
FOLLOWUP
Try this code.
Dim objExcel, objWorkbook, ad, FilePath
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
For Each ad In objExcel.AddIns
If ad.Name = "Converteam.xla" Then
FilePath = ad.Path & "\Converteam.xla"
Exit For
End If
Next
objExcel.Workbooks.Open (FilePath)
Set objWorkbook = objExcel.Workbooks.Open("C:\Folder\Test_PO.xls")
objExcel.Run "Data_Analysis_Converteam"
objWorkbook.Close
objExcel.Quit
Set objWorkbook = Nothing
Set objExcel = Nothing
WScript.Echo "Finished."
WScript.Quit
EXPLANATION:
When you use CreateObject, the Add-Ins are not installed by default. Please see this link.
Topic: Add-ins do not load when using the CreateObject command in Excel
Link: http://support.microsoft.com/kb/213489/
You have to load the Add-In and then call the relevant macro. Also the name of your macro is not Data_Analysis but Data_Analysis_Converteam
HTH
To add to Siddhart's answer - you can load the addins you require in a VBScript like this:
objExcel.RegisterXLL("analys32.xll") 'For XLL addins
objExcel.Workbooks.Open(objExcel.LibraryPath & "\analysis\atpvbaen.xla") 'For standard XLA addins
objExcel.Workbooks.Open("C:\Program Files\MyAddins\MyAddin.xla") 'for custom XLA addins

Excel 2003 VBA: Move a sheet into a new workbook that is referenced by a variable

I have a function that is meant to run the ShowPages() command of a PivotTable and then save each sheet to a separate file.
Here's how I wish I could do it:
Sub Split()
ThisWorkbook.Sheets("Data").PivotTables("Data").ShowPages PageField:="Codename"
Dim newWb As Workbook
For Each s In ThisWorkbook.Sheets
If s.Name <> "Data" Then
Set newWb = s.Move #This is the line I'm trying to work out
newWb.SaveAs Filename:="C:\Export\" + s.Name + ".xls"
newWb.Close
End If
Next s
End Sub
Unfortunately, this is running into a bunch of issues to do with not having created objects and suchlike (understandably). What is the most sensible way to do this?
Sub Split()
ThisWorkbook.Sheets("Data").PivotTables("Data").ShowPages PageField:="Codename"
Dim newWb As Workbook
For Each s In ThisWorkbook.Sheets
If s.Name <> "Data" Then
''Added by Soldieraman
Dim sheetName As String
sheetName = s.Name
Set newWb = Workbooks.Add
s.Move before:=newWb.Sheets(1)
Application.DisplayAlerts = False
newWb.Sheets(Array("Sheet1", "Sheet2", "Sheet3")).Delete
Application.DisplayAlerts = True
''Edited by soldieraman
newWb.SaveAs Filename:="C:\Export\Test" & sheetName & ".xls"
newWb.Close
End If
Next s
End Sub
Although this is old, and the accepted answer by soldieraman is very nice, just wanted to add one thing. The Excel VBA Sheets.Copy and Sheets.Move methods have a very nice feature. They take either of two optional arguments, "Before" or "After", to position a moved/copied sheet. The Excel documentation notes that:
If you don't specify either Before or After, Microsoft Excel
creates a new workbook that contains the moved [copied] sheet.
So, it is almost surprising, but you can just say:
Sheets(sheetname).Move
in the accepted answer, in place of:
Set newWb = Workbooks.Add
s.Move before:=newWb.Sheets(1)
Application.DisplayAlerts = False
newWb.Sheets(Array("Sheet1", "Sheet2", "Sheet3")).Delete
Application.DisplayAlerts = True
The rest of soldieraman's code would work fine with this simplification.