Excel VBA: Can Shell run a macro in a workbook in another Excel instance - excel

For example something like this to open the workbook in a new instance and then start the macro:
Shell(Excel.exe workbook.xlsm!macro1)
Or if the workbook was already open then:
Shell(xlObject macro1)
Most important thing is to use Shell so as to allow the code to continue whilst the macro runs separately. If not possible then perhaps I could Shell(file.bat) to a batch file that would do the same. What would the batch file look like?
Thank you.

You cannot execute VBA code inside a host application from the command line - that includes Shell.
There are two alternatives, though (with Excel#1 being the current open file and Excel#2 being the one you want to run the code in):
Put the code you want to run in the Excel #2 workbook's Workbook_Open event handler so it will execute every time you open that file - independet of how it was opened.
Have Excel#1 create a new Excel.Application object in VBA and open Excel#2 in that application. You could now call the Run() method on the Excel#2's application object to execute code from Excel#2, but this will be done synchronous to the Excel#1's code. You can use the Excel#2 application's OnTime() method though for delayed macro execution, in which case Excel#2's application will call the code when the delay has passed and the code runs asynchronous in Excel#2's application.
Sample code for Option 2 could look like this:
Public Function RemoteRun(ByVal strFile As String) As Application
Dim app As Application
Dim wb As Workbook
Set app = New Application
Set wb = app.Workbooks.Open(strFile)
app.OnTime Now + 1 / 24 / 60 / 60, "RemoteMacro"
Set RemoteRun = app
End Function
Make sure to store the return value (the Excel#2's application object) somehwere so it won't automatically close (it still has to run RemoteMacro asynchronously). Setting its Visible property to True will work as well if you don't want Excel#1's code to manage the lifetime of Excel#2's application object.

Related

Apply MS Project SetTaskMode via Excel VBA

I am reading a sheet in Excel and creating a Microsoft Project Plan of tasks, Work, Notes, etc.
The code is being executed out of MS Excel.
How can I get the Active.Project to assign, SetTaskMode Manual:= False?
I receive an error, please note Application.Visible = True.
As far as .Application.Methods (Project) go, I am able to invoke the Application.About screen, i.e on Sub execution the MS Project About screen opens up, however after that line, it stops.
Basically, I would like to set the Active Sheet Task Mode to be set to 'automatically scheduled' as the default for all tasks as they are being imported.
The project property in question is NewTasksCreatedAsManual and is used like this to make all new tasks auto-scheduled:
ActiveProject.NewTasksCreatedAsManual = False
Alternatively, to set the task mode to auto-schedule on an individual task, use the Manual property like this:
tsk.Manual = False
' or to change to manually scheduled
tsk.Manual = True

Executing VB script from Spring Boot Application

I want to execute a VB script from Spring Boot application, the script is like:
' Creating a file as test acces to macro
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.CreateTextFile("C:\excel\FLAG_TEST")
Set objExcel = CreateObject("Excel.Application")
Set objWorkbook = objExcel.Workbooks.Open("C:\excel\excelFile.xls")
objExcel.Application.EnableEvents = False
objExcel.Application.DisplayAlerts = False
objExcel.Application.Run "excelFile.xls!executeMacroFunction"
objExcel.Application.Quit
I tried to execute the script from Spring Boot service by:
Runtime.getRuntime().exec(new String[]{"C:\\Windows\\System32\\wscript.exe", "C:/vb/script.vbs"});
The above line code does not work on the application deployed on Tomcat 9 (it works fine when running as Spring Boot App on Eclipse)
Then I tried to execute the script via a batch file launched from the app
On batch file, I tried to execute the VB script by
rem First way
Set wscript = CreateObject("WScript.Shell")
wscript.Run "C:/vb/script.vbs"
--------------------
rem Second way (System 64bit)
C:\Windows\System32\wscript.exe C:/vb/script.vbs
--------------------
rem Third way (System 64bit)
wscript C:/vb/script.vbs
And running the batch file from Java with different ways too:
// First way
ProcessBuilder processBuilder = new ProcessBuilder("C:/batch/executor.bat");
final Process process = processBuilder.start();
// Second way
Process process = Runtime.getRuntime().exec("cmd /c start \"\" C:/batch/executor.bat");
// Third way
Process process = Runtime.getRuntime().exec(
"cmd /c start \"\" C:/batch/executor.bat",
null,
new File("C:\\Windows\\SysWOW64"));
All these ways do not work, the scripts have no problem since they work when I run manually the batch file (by double click)
On the execution of the macro from Spring Boot, the test file (FLAG_TEST) is created and then the execution is blocked at the line:
Set objExcel = CreateObject("Excel.Application")
Am I missing something ?...Thanks a lot in advance !
Tried also with Jacob DLL to run the Macro inside the excel file, it also didn't work for me within a Tomcat server
I decided at the end to abandon any kind of external tool and do the thing within Spring Boot, parsing the Excel file via an Excel Java API and migrating the Macro program to Java: JExcel
<dependency>
<groupId>net.sourceforge.jexcelapi</groupId>
<artifactId>jxl</artifactId>
<version>2.6.12</version>
</dependency>
Unlike some other Excel parsing APIs, the Jexcel get the cell text as it is: String, Number, Boolean, Formula (its displayed result), no need to handle the different cases of content type
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import jxl.WorkbookSettings;
// Set Encoding 1252 that supports many European languages (special characters included)
WorkbookSettings workbookSettings = new WorkbookSettings();
workbookSettings.setEncoding("Cp1252");
Workbook workbook = Workbook.getWorkbook(new File(EXCEL_FILE_LOCATION), workbookSettings);
Sheet sheet = workbook.getSheet(0);
Cell cellDemo = sheet.getCell(0, 0); // Or sheet.getCell("A1");
// Get the displayed cell centent as a text
String cellContent = cellDemo.getContents();
System.out.print("Cell A1 centent:" + cellContent);
The Java parsing makes the exception handling of data validation easier and more precise, no kind of abstract HMI error message (Error occurred wile processing the Excel file...)
Turns out that the Excel Java reading API implementation took less time than the several attempts of runing the Macro externally :D

Excel file remaining locked for editing after use

I have a Windows Forms application with an OpenFileDialog. The user clicks a "Process" button and the application goes through the file - an Excel spreadsheet - and processes the data in it. All of this works as expected with one caveat.
After the application is done processing, the file remains locked for editing so when I open the file to make changes, I get this message:
If I close the application completely, the file is unlocked so I'm assuming the application is just holding onto the file for longer than it should. I'm guessing there should be some sort of Close() method or something that will release the resources but I can't figure out exactly what I need. I tried using Dispose() and wrapping my code in a Using block which I thought destroyed everything automatically but no luck.
Here's my code:
Using excel = New ExcelPackage(OpenFileDialog1.OpenFile)
Dim ws = excel.Workbook.Worksheets.First()
'Process data in ws...
OpenFileDialog1.Dispose() 'Doesn't seem to release the file
excel.Dispose() 'Doesn't seem to release the file
End Using
The OpenFileDialog.OpenFile Method returns a Stream object that likely is not being closed by the ExcelPackage.
To ensure that the stream is released, use the following pattern.
Using strm As IO.Stream = OpenFileDialog1.OpenFile
Using excel = New ExcelPackage(strm)
' ...
End Using
End Using

How to make 'Workbook_WindowActivate' be called when I'm using dual display?

This trigger(and Workbook_WindowDectivate) can successfully be called when I switch window from a workbook to another workbook IN THE SAME SCREEN, but when I switch to a workbook in another screen, it doesn't work.
It seems they belong to 2 different processes, I can find there are 2 Excel.exe in task manager.
I have a lot of datas and a lot of slicers in one of my workbook which make my sheets run very slowly, but I need keep the global setting 'AutoCalculate' on.
So I'm trying to use a macro to desable it's calculation.
I frequently open multiple windows in 2 screens when working, so my intent is to make this macro can be called when I focus on a workbook in another screen.
Assuming there are two distinct processes, you can't.
It's two distinct instances of Excel.Application, each with their own Workbooks collection: you could call one instance "Vegas", and say "what happens in Vegas, stays in Vegas".
Unless... unless your code completely owns that other instance:
Private WithEvents OtherExcel As Excel.Application
Private Sub Workbook_Open()
Set OtherExcel = New Excel.Application
OtherExcel.Visible = True
End Sub
Private Sub OtherExcel_WindowActivate(Wb As Workbook, Wn As Window)
End Sub
Private Sub OtherExcel_WindowDeactivate(Wb As Workbook, Wn As Window)
End Sub
...with a number of caveats:
It opens a new Excel instance every time
It won't handle a 3rd instance
If the execution context dies, the OtherExcel object is gone
Execution context dies whenever the VBE decides a code change requires recompiling
Or whenever an unhandled error occurs
Or when an End statement is encountered
If the OtherExcel instance is closed the object is gone; if another instance is then started, the OtherExcel object is still gone.
You could work around these limitations, by exposing a macro that re-assigns OtherExcel on demand. "Attaching" the OtherExcel reference to an already-running 2nd instance of Excel could probably be done (GetObject comes to mind), but might be unreliable or tricky.

Excel fails to throw errors on Workbooks.Open or Workbook.Save methods on files that are in use

Our code essentially does the following:
1) It creates an Excel.Application object, and invokes .Workbooks.Open to open a file from a network location
2) It makes a minor change to the open Workbook
3) It invokes the .Save() method to save the workbook
This is causing a problem when the file is currently in use because
1) NO error is raised on .Workbooks.Open - The workbook simply gets opened in ReadOnly mode, but no messages or nothin' are shown to the user. So unless the user pays close attention and looks at the Title Bar, he or she will have NO idea that the document has actually been opened in ReadOnly mode
BUT the worst thing is
2) The .Save() method on the WorkBook object raises NO error WHATSOEVER. Instead it just goes ahead and saves the document to the %UserProfile%\Documents folder. Not only does it raise no error that WE can catch in code, it shows no message or warning to the USER either, so they remain blissfully unaware of the fact that they are no longer working on the original document in the Network Location, but on a local copy of same instead.
So the questions are:
1) Can we either force Excel to show a message to the END USER or raise an error on the .Workbooks.Open method so we can handle it in code? At the moment all I can do is check the workbook's .ReadOnly property, but that will give me no clue as to whether the workbook is ACTUALLY Read Only, or whether it was open in Read Only mode because it is in use by another user, let alone tell us in code, or the user through a message box, by WHOM the workbook might be in use.
2) Can we force Excel to raise an error or prompt the user on the workbook's .Save method, rather than simply saving it somewhere local without any indication to anyone!?!?
Sorry if I sound exasperated.... you should have heard the customer....
'Please note that oXApp is a Microsoft.Office.Interop.Excel.Application that has been instantiated correctly.
Dim oWBS As Microsoft.Office.Interop.Excel.Workbooks = Nothing
Dim oWBK As Microsoft.Office.Interop.Excel.Workbook = Nothing
oWBS = oXApp.Workbooks
oWBK = oWBS.Open(sFile) 'No error raised here, nothing. Document is opened in ReadOnly mode. sFile contains a UNC path to a file that is in use by another user.
oWBK.Save() 'Again, no error raised, but while oWBK.FullName points at the UNC path BEFORE the Save, it now refers to a local path in %UserProfile%\Documents

Resources