Run a macro using VBS on already opened excel - vba

I would like to run a macro on an Excel using VBS code. My Excel will be always open. I am using below code for that.
Excel: main.xlsm, macro name: Inc
Option Explicit
Dim xlApp, xlBook
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("E:\Main.xlsm", 0, False)
xlApp.Run "Inc"
xlBook.Close
xlApp.Quit
Set xlBook = Nothing
Set xlApp = Nothing
WScript.Quit
The problem is whenever I run the code, it looks like the Excel trying to open in read only mode. As soon as the VBS runs, I am getting "save changes window" and saving the sheet as a copy.
I would like to save the changes on the same sheet rather than saving it as a new copy.

Excel lets you save a copy because you create a new instance of Application object, so you open the workbook again in read-only mode. To get a reference to Application object of the particular running instance of Excel with already opened workbook you should use the following lines:
Set xlBook = GetObject("E:\Main.xlsm")
Set xlApp = xlBook.Application
instead of
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("E:\Main.xlsm", 0, False)
Then you just need to save that workbook with .Save.

You are creating a new Instance with Set xlApp = CreateObject("Excel.Application"), also the WB is then opened twice. Easiest fix, if you just close the WB before executing your code, then it should work fine. Also when closing use xlBook.Close SaveChanges:=True, no prompt should appear then.

Related

Opening workbook from file and updating link in original workbook

I'm trying to write a macro in VBA, that will open another Workbook using a PathFile specified in a cell (this works), updates link in workbook in which macro is used (doesn't work) and closes the PathFile workbook (works)
This is a code:
Sub UpdateRaw()
Dim CurrWb As Workbook
Dim FilePath As String
Dim book As Excel.Workbook
Set CurrWb = ActiveWorkbook
FilePath = Range("I1").Value
Dim app As New Excel.Application
app.Visible = True 'so we can see whether correct file is being opened
Set book = app.Workbooks.Open(FilePath)
CurrWb.Activate
Worksheets("Raw_vs_Actual").EnableCalculation = False
Worksheets("Raw_vs_Actual").EnableCalculation = True
book.Close SaveChanges:=False
app.Quit
Set app = Nothing
End Sub
Going step by step I found that command CurrWb.Activate doesn't take me back to my original Workfile. My suspicion is that by opening new Excel Application I can't get back to the CurrWb (ActiveWorkbook). Is there a workaround? I need this so my INDIRECT function doesn't return #REF.
I'm using Excel 2010 in case it's important.
I think Set book = app.Workbooks.Open(FilePath) shall be enough, but if not refresh the workbook:
book.RefreshAll
for opened workbook. For the workbook that contains the macro, use
ThisWorkbook.RefreshAll

Using other workbook without opening it

I created Excel macro, in which I'm searching current date in other, closed workbook and getting the number of the row where this date is. Everything works perfectly, but only if I'm opening this other workbook.
Is there a possibility to make the code works without opening this workbook? Or maybe it's possible to make this workbook not to appear, because I don't want it to appear on the screen?
I've tried many methods, e.g. Application.ScreenUpdating = false or ActiveWorkbook.Windows(1).Visible = False but it doesn't work the way I want it.
You need to create a new Excel Application to be able to hide the Window:
Dim xlApp As New Excel.Application 'New Excel Application
Dim xlWB As Excel.Workbook 'Workbook Object
xlApp.Visible = False 'Hide Application
Set xlWB = xlApp.Workbooks.Open("PATH TO FILE") 'Open File in new App
'do something here
xlWB.Sheets(1).Cells(1, 1).Value = "Hello, this is a Test"
xlWB.Close 'Close Workbook (Use SaveChanges:=True to save changes)
Set xlWB = Nothing 'Clear Object
xlApp.Quit 'Quit Excel App
Set xlApp = Nothing 'Clear Object

Save and close workbook without prompting after running a macro?

I want to save and close the Excel file in which I am executing a macro (Module : modBex, Sub: Test) via VBScript.
The following code is working fine, except the Excel file (macro_file.xlsm) doesn't get saved.
Here is my code:
Option Explicit
Dim xlApp, xlBook
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("C:\macro_file.xlsm", 0, True)
xlApp.Run "modBex.Test"
xlApp.DisplayAlerts = False
xlBook.Save
xlApp.Quit
Set xlApp = Nothing
Set xlAddin = Nothing
Set xlBook = Nothing
WScript.Quit
Change the line
Set xlBook = xlApp.Workbooks.Open("C:\macro_file.xlsm", 0, True)
to
Set xlBook = xlApp.Workbooks.Open("C:\macro_file.xlsm", 0, False)
as I believe that flag is setting the file to open as Read Only, leading to an error when saving the document.
In addition to this, if you leave any and all alert suppressing (ie .DisplayAlerts = False)until you know you have working code, then it makes things like this easier to spot.

Difference between CreateObject("Excel.Application") .Workbooks.Open and just Workbooks.Open

I am currently using Workbooks.Open to process a large number of files contained in a directory. But opening and closing these files make the files appear in the task bar and I wanted to avoid the constant flickering.
I got a suggestion from that I can use CreateObject to create a new instance since that opens a new Excel instance which is hidden.
Is there any other difference between the two ways of opening new workbooks in terms of performance?
Also, should I just use one instance of Excel created using CreateObject to open all Workbooks or do I need to create one instance for each workbook I have to process (which seems like a waste of lot of memory and less speed)?
Workbooks.Open uses the current MS Excel instance and CreateObject(“Excel.Application”) creates a new MS Excel instance. You can read up on CreateObject here.
Simply issuing a Workbooks.Open after creating a new instance will not ensure that the workbooks open in the new instance. You will have to bind with it. For example
Dim oXLApp As Object, wb As Object
Set oXLApp = CreateObject("Excel.Application")
'~~> Hide Excel
oXLApp.Visible = False
'~~> Open files
Set wb = oXLApp.Workbooks.Open("C:\Sample.xls")
Regarding your other question
Also, should I just use one instance of Excel created using CreateObject to open all Workbooks or do I need to create one instance for each workbook I have to process
You don't need several instances. You can work with one instance. For example
Dim oXLApp As Object, wb As Object
Set oXLApp = CreateObject("Excel.Application")
'~~> Hide Excel
oXLApp.Visible = False
'~~> Open files
Set wb = oXLApp.Workbooks.Open("C:\Sample1.xls")
'
'~~> Do some Stuff
'
wb.Close (False)
'~~> Open files
Set wb = oXLApp.Workbooks.Open("C:\Sample2.xls")
'
'~~> Do some Stuff
'
wb.Close (False)
'
'~~> And So on
'
Late binding is slightly slower than early binding, but you may not even notice the difference. Yes, you can use just use one instance for all the workbooks. Note that this:
Dim xl As New Excel.Application
xl.Workbooks.Open "z:\docs\test.xlsm"
Will not be visible unless you say:
xl.Visible = True
Be sure to close any instances in your error trap.

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.