I currently have the below code which opens a workbook in a new instance of excel (The workbook that is opened has an on open macro).
However when the code is running in the new instance, this also takes up the existing instance of excel and only frees it once the workbook open macro has run.Is there a way to open excel in a new instance and detach/stop the code from the existing workbook immediately?
Please see code below.
Sub OpenWBInNewInstance()
Dim xApp As Excel.Application
Set xApp = New Excel.Application
xApp.Visible = True
Dim wb As Excel.Workbook
Set wb = xApp.Workbooks.Open("Z:\MI\Not Purchased Detail\Not Purchased Detail Disposal Marketing Template.xlsb")
End Sub
Code execution runs on a single thread in VBA, so you can't do what you're asking because the execution won't move to the next line until the entire Workbooks.Open line has been processed - which includes the Workbook_Open event in the other workbook.
A possible workaround it to use VBScript instead:
Sub OpenWBInNewInstance()
Open Environ$("USERPROFILE") & "\Desktop\temp.vbs" For Output As #1
Print #1, "Set xl = CreateObject(""Excel.Application"")"
Print #1, "xl.Workbooks.Open ""Z:\MI\Not Purchased Detail\Not Purchased Detail Disposal Marketing Template.xlsb"""
Close #1
Shell Environ$("USERPROFILE") & "\Desktop\temp.vbs"
'// You will need some kind of hook here to set the workbook in other instance...
Related
I am using Access 2007. In my Access file I have VBA code that opens an Excel
workbook when the Access program begins. The Excel workbook remains open
while the program is running. I use this code to open the workbook:
Public xl As Object
Public wb1 As Object
Set xl = New Excel.Application
Set wb1 = xl.Workbooks.Open("c:\Book1.xlsx")
Now while the program is running I may need to open a second Excel workbook,
get some data from it, then close it. I used this code:
Public wb2 As Object
Set wb2 = xl.Workbooks.Open("c:\Book2.xlsx")
But this doesn't work. It seems that the first workbook may have closed because
if I do debug.print Workbooks.Count the response is "0".
Any suggestions on how to open a second workbook and still have the first workbook open?
Should I create a second instance of Excel and use that to open the second workbook?
Thank you.
You may have more luck with this procedure instead:
Sub OpenExcel(fName As String)
Dim xlApp As Object
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If Err.Number <> 0 Then
'Excel wasn't running, start it from code
Set xlApp = CreateObject("Excel.Application")
End If
On Error GoTo 0
xlApp.Workbooks.Open (fName)
End Sub
With your code it's possible that Excel was opening but the second workbook did not default to visible, which could be set with xl.Visible = True. Alternatively, a second xl object could have helped.
Regardless, this method is safer is a number of ways.
Make sure when you're done, make sure you clean up (and free up memory) with something like xlApp.Quit and Set xlApp = Nothing.
In fact, I'd suggest you reboot right now... before you do, take a look at the running processes in your Task Manager - I wouldn't be surprised if you have several "invisible" instances of Excel running. :)
I want to search through existing Excel files with a macro, but I don't want to display those files when they're opened by the code. Is there a way to have them open "in the background", so to speak?
Not sure if you can open them invisibly in the current excel instance
You can open a new instance of excel though, hide it and then open the workbooks
Dim app as New Excel.Application
app.Visible = False 'Visible is False by default, so this isn't necessary
Dim book As Excel.Workbook
Set book = app.Workbooks.Add(fileName)
'
' Do what you have to do
'
book.Close SaveChanges:=False
app.Quit
Set app = Nothing
As others have posted, make sure you clean up after you are finished with any opened workbooks
If that suits your needs, I would simply use
Application.ScreenUpdating = False
with the added benefit of accelerating your code, instead of slowing it down by using a second instance of Excel.
To open a workbook as hidden in the existing instance of Excel, use following:
Application.ScreenUpdating = False
Workbooks.Open Filename:=FilePath, UpdateLinks:=True, ReadOnly:=True
ActiveWindow.Visible = False
ThisWorkbook.Activate
Application.ScreenUpdating = True
Using ADO (AnonJr already explained) and utilizing SQL is possibly the best option for fetching data from a closed workbook without opening that in conventional way. Please watch this VIDEO.
OTHERWISE, possibly GetObject(<filename with path>) is the most CONCISE way. Worksheets remain invisible, however will appear in project explorer window in VBE just like any other workbook opened in conventional ways.
Dim wb As Workbook
Set wb = GetObject("C:\MyData.xlsx") 'Worksheets will remain invisible, no new window appears in the screen
' your codes here
wb.Close SaveChanges:=False
If you want to read a particular sheet, need not even define a Workbook variable
Dim sh As Worksheet
Set sh = GetObject("C:\MyData.xlsx").Worksheets("MySheet")
' your codes here
sh.Parent.Close SaveChanges:=False 'Closes the associated workbook
Even though you've got your answer, for those that find this question, it is also possible to open an Excel spreadsheet as a JET data store. Borrowing the connection string from a project I've used it on, it will look kinda like this:
strExcelConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & objFile.Path & ";Extended Properties=""Excel 8.0;HDR=Yes"""
strSQL = "SELECT * FROM [RegistrationList$] ORDER BY DateToRegister DESC"
Note that "RegistrationList" is the name of the tab in the workbook. There are a few tutorials floating around on the web with the particulars of what you can and can't do accessing a sheet this way.
Just thought I'd add. :)
A much simpler approach that doesn't involve manipulating active windows:
Dim wb As Workbook
Set wb = Workbooks.Open("workbook.xlsx")
wb.Windows(1).Visible = False
From what I can tell the Windows index on the workbook should always be 1. If anyone knows of any race conditions that would make this untrue please let me know.
The problem with both iDevlop's and Ashok's answers is that the fundamental problem is an Excel design flaw (apparently) in which the Open method fails to respect the Application.ScreenUpdating setting of False. Consequently, setting it to False is of no benefit to this problem.
If Patrick McDonald's solution is too burdensome due to the overhead of starting a second instance of Excel, then the best solution I've found is to minimize the time that the opened workbook is visible by re-activating the original window as quickly as possible:
Dim TempWkBk As Workbook
Dim CurrentWin As Window
Set CurrentWin = ActiveWindow
Set TempWkBk = Workbooks.Open(SomeFilePath)
CurrentWin.Activate 'Allows only a VERY brief flash of the opened workbook
TempWkBk.Windows(1).Visible = False 'Only necessary if you also need to prevent
'the user from manually accessing the opened
'workbook before it is closed.
'Operate on the new workbook, which is not visible to the user, then close it...
Open the workbook as hidden and then set it as "saved" so that users are not prompted when they close out.
Dim w As Workbooks
Private Sub Workbook_Open()
Application.ScreenUpdating = False
Set w = Workbooks
w.Open Filename:="\\server\PriceList.xlsx", UpdateLinks:=False, ReadOnly:=True 'this is the data file were going to be opening
ActiveWindow.Visible = False
ThisWorkbook.Activate
Application.ScreenUpdating = True
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
w.Item(2).Saved = True 'this will suppress the safe prompt for the data file only
End Sub
This is somewhat derivative of the answer posted by Ashok.
By doing it this way though you will not get prompted to save changes back to the Excel file your reading from. This is great if the Excel file your reading from is intended as a data source for validation. For example if the workbook contains product names and price data it can be hidden and you can show an Excel file that represents an invoice with drop downs for product that validates from that price list.
You can then store the price list on a shared location on a network somewhere and make it read-only.
Open them from a new instance of Excel.
Sub Test()
Dim xl As Excel.Application
Set xl = CreateObject("Excel.Application")
Dim w As Workbook
Set w = xl.Workbooks.Add()
MsgBox "Not visible yet..."
xl.Visible = True
w.Close False
Set xl = Nothing
End Sub
You need to remember to clean up after you're done.
In excel, hide the workbooks, and save them as hidden. When your app loads them they will not be shown.
Edit: upon re-reading, it became clear that these workbooks are not part of your application. Such a solution would be inappropriate for user workbooks.
Instead of having all the macro's stored in each workbook, we would like to have them stored in one global one. We tried using Personal.xlsb file, however every time excel crashes or system administrator forced restart with excel open it created personal.v.01 ....v.100 files, and they interfered with each other, got corrupted etc.. So instead we are trying to add a small macro to each excel workbook we make which then should open a global excel workbook with all the macros, however it does not open it(normal.xlsb), where is the problem? If I manually run it it works fine, it just does not autorun..
Option Explicit
Public Sub Workbook_Open()
Dim sFullName As String
Dim xlApp As Excel.Application
Dim wbReturn As Workbook
sFullName = "Z:\Dokumentstyring\normal.xlsb"
Set xlApp = GetObject(, "Excel.Application") 'need to do so to open it in same instance otherwise the global macros can not be called.
Set wbReturn = xlApp.Workbooks.Open(filename:=sFullName, ReadOnly:=True)
If wbReturn Is Nothing Then
MsgBox "Failed to open workbook, maybe z drive is down?"
Else
ThisWorkbook.Activate'Dont know how to pass object to modules, so instead activate it and in createbutton set wb= activeworkbook..
Application.Run ("normal.xlsb!CreateButtons")
End If
End Sub
Public Sub Workbook_BeforeClose(Cancel As Boolean)
Dim wb As Workbook
For Each wb In Application.Workbooks
If InStr(UCase(wb.Name), "PARTSLIST") > 0 And wb.Name <> ThisWorkbook.Name Then Exit Sub
Next wb
On Error Resume Next
Workbooks("normal.xlsb").Close
Workbooks("filter.xlsx").Close
End Sub
You create your addin, as just an empty workbook, holding nothing but the code
Like this
Then you add a reference to it, in the workbook that you wish to use, in VBA, like this. My Documents, is a folder on a network drive, not "my documents" local.
And then you can call like so.
So based on input from #Nathan_Sav and #Ralph I have come to a partly good solution:
I have called my addinn Normal and saved this on Z:Dokumenstyring\Normal.xlam
I then removed all the code in Thisworkbook of Normal:
Private Sub Workbook_Open()
Dim ExcelArgs As String
Dim arg As String
ExcelArgs = Environ("ExcelArgs")
'Call deleteMacros.deletePersonalFiles
'MsgBox ExcelArgs
If InStr(UCase(ExcelArgs), "CREO,") > 0 Then
Application.DisplayAlerts = False
If Len(ExcelArgs) > Len("CREO,") Then
arg = Split(ExcelArgs, ",")(1)
Call Creo.addNewPartToPartslist(arg)
End If
Application.DisplayAlerts = True
End If
If InStr(UCase(ExcelArgs), "DOKLIST,") > 0 Then
Application.DisplayAlerts = False
If Len(ExcelArgs) > Len("DOKLIST,") Then
arg = Split(ExcelArgs, ",")(1)
Call ProsjektListen.dbDumpDocOut(arg)
End If
Application.DisplayAlerts = True
End If
and put this in a new workbook called Z:Dokumenstyring\Creo.xlsm
I have so edited all my bat files(which previously were using personal.xlsb):
echo "Launch excel"
Set ExcelArgs=CREO,ADDPART
"C:\Program Files (x86)\Microsoft Office\OFFICE16\Excel.exe" /x /r "z:\Dokumentstyring\Creo.xlsm"
So when I run the bat file it adds a parameter to enviroment, start creo.xlsm, which then starts the addin which launch my userform.
So if I now want to update the look of that that userform I do this by modifying the Z:Dokumenstyring\NormalDebug.xlam, then i save a copy which i write over Z:Dokumenstyring\Normal.xlam and I also told every user to not copy the addin to the default location in excel but keep it in Z:Dokumenstyring\Normal.xlam.
My shapes in my excel sheets seems to work with just the macro name in the procedure, however there might be an conflict if two procedures have the same name, but located in different procedures. So I also altered this to
ws1.Shapes(tempName).OnAction = "Normal.xlam!Custom_Button_Click"
However every click starts a new instance of the addin, how to avoid this?
I'm trying to get Word to open an Excel document whenever a document based on a specific template is created.
Here is my macro
Sub AutoNew()
Dim oExcel As Excel.Application
Dim oWB As Workbook
Set oExcel = New Excel.Application
Set oWB = oExcel.Workbooks.Open("E:\Letters.xlsx")
End Sub
When I double-click the template, it brings up a document based on the template just fine, but the macro doesn't run.
It shows up in the list of macros in the template, but attempting to run it doesn't do anything.
As has mentioned KazJaw, make app visible
Sub AutoNew()
Dim oExcel As Excel.Application
Dim oWB As Workbook
Set oExcel = New Excel.Application
Set oWB = oExcel.Workbooks.Open("E:\Letters.xlsx")
oExcel.Visible = true
End Sub
A disadvantage is, that excel application is launching as a new task (see tak manager) in case of another calling the macro - every document is opened in its own task.
The correct way is use API for launching a document in registered application, for example here: http://access.mvps.org/access/api/api0018.htm
Or one-row workaround, ugly, but works great:
Shell "cmd.exe /c start D:\a\test.xlsx"
Note that template with macro must have extension .xltm, not .xltx.
Let's say I want to program a VBA code in an external program that opens an Excel file, runs a macro, saves (and say yes to any pop up windows), and close Excel. Is it possible to do so? If so, how would I go about implementing it?
You can launch Excel, open a workbook and then manipulate the workbook from a VBScript file.
Copy the code below into Notepad.
Update the 'MyWorkbook.xls' and 'Sheet1' parameters.
Save it with a vbs extension and run it.
Option Explicit
On Error Resume Next
ExcelMacroExample
Sub ExcelMacroExample()
Dim xlApp
Dim xlBook
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("C:\MyWorkbook.xls")
xlBook.Sheets("Sheet1").Cells(1, 1).Value = "My text"
xlBook.Sheets("Sheet1").Cells(1, 1).Font.Bold = TRUE
xlBook.Sheets("Sheet1").Cells(1, 1).Interior.ColorIndex = 6
xlBook.Save
xlBook.Close
xlApp.Quit
Set xlBook = Nothing
Set xlApp = Nothing
End Sub
This code above launches Excel opens a workbook, enters a value in cell A1, makes it bold and changes the colour of the cell. The workbook is then saved and closed. Excel is then closed.
Depending on what you are trying to achieve you may also 'control' Excel via (OLE) Automation from another application such as Access or Word or from your own application written in another environment such as Visual Basic (6). It is also possible to achieve this via .Net using a language of your choice (although some are easier to implement than others).
Are you wanting to control Excel from an external application or simply trigger a VBA macro in an existing workbook from the outside?
Again, depending on your intention, the workbook could have an Auto Open macro which could be conditional run based on an external value (say an ini file or database value).
I can think of several ways to do this.
You can start excel by creating a file with NotePad or a similar text editor.
Here are some steps:
Launch NotePad
Add the following line of text. Replace test.xlsm with the name and path for your file:
start Excel.exe "C\test.xlsm"
Save the file as "Test.bat".
Run the batch file.
The batch file should launch Excel and then open your file. The code in your workbook should run
OR
Again, using Notepad.
Option Explicit
On Error Resume Next
ExcelMacroExample
Sub ExcelMacroExample()
Dim xlApp
Dim xlBook
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("C:\MyWorkbook.xls", 0, True)
xlApp.Run "MyMacro"
xlApp.Quit
Set xlBook = Nothing
Set xlApp = Nothing
End Sub
Or, this.
'Code should be placed in a .vbs file
Set objExcel = CreateObject("Excel.Application")
objExcel.Application.Run "'C:\Users\Ryan\Desktop\Sales.xlsm'!SalesModule.SalesTotal"
objExcel.DisplayAlerts = False
objExcel.Application.Quit
Set objExcel = Nothing
Now, this isn't 'an external command', but the Windows Task Scheduler will do a nice job of opening that file for you, and once it is opened, you can run a tiny script like the one you see below.
Private Sub Workbook_Open()
Call CommandButton1_Click
End Sub
https://www.sevenforums.com/tutorials/11949-elevated-program-shortcut-without-uac-prompt-create.html