I am trying to ensure that an Excel file is not left open if a Word application that is gathering data from it via a macro suddenly crashes.
The macro handles most errors using the code below, but I want to ensure that the Excel file isn't left hanging open in the face of an unhandled event. Such an event might be the user closing the word document from the task manager while the macro is running.
Public Function GatherDataFromExcel(x) As Collection
On Error GoTo CloseExcel
Dim path_file_excel As String
path_file_excel = "\path to file\file.xlsx"
Dim objXL As Object ' Excel.Application
Dim objBook As Object ' Excel.Workbook
Set objXL = CreateObject("Excel.Application")
On Error Resume Next
Set objBook = objXL.Workbooks.Open(path_file_excel)
On Error Resume Next
'Code that gathers data and returns that data from the function
CloseExcel:
If Not objBook Is Nothing Then
objBook.ActiveWorkbook.Close
objBook.Close
Set objBook = Nothing
If Not objXL Is Nothing Then
Set objXL = Nothing
End If
End If
End Function
I have closed the word document mid execution to check, and indeed the excel file is left hanging open. Is there any way to prevent this from happening?
If Word crashes you are going to need a different process to close Excel.
A few options:
Show Excel to the user so that the user can close Excel objXL.visible = true
If your VBA error handler does run you probably want to change:
objBook.ActiveWorkbook.Close
objBook.Close
To
objBook.Close False ' Close workbook without saving changes
objXL.Quit ' Exit Excel
As Freeflow suggested, have another process (e.g. timer event in Excel or a separate VBScript process) that closes Excel if it can't find the Word document
Related
I'm having an VB6 application that opens an excel macro enabled file using workbooks.open method. Inside this file, there is an userform that gonna be automatically opened when the file is opened. The problem is the workbooks.open method in vb6 application keeps running and does not jump to next line even when I close my userform (I do have codes to close workbook, quit excel app when the userform is closed). I can only close the interface of my userform but Excel still running in background. As long as I dont close the Excel app in task manager, my vb6 does not terminate excel process and of course it will not jump to next line either.
Here is my code in vb6 to open excel file that contains the userform above
As I said, workbooks.open method works but it does not terminate and keeps the excel app runnning in background
P/s: don't mind the Japanese characters
Private Sub Form_Load()
Dim xlapp
Dim xlwkb
If Not App.PrevInstance Then
Set xlapp = CreateObject("excel.application")
Me.Hide
On Error Resume Next
Set xlwkb = xlapp.workbooks.open("C:\Users\david\Desktop\sale-system\fixedfile.xlsm", Readonly:= True)
Set xlwkb = Nothing
If Not xlapp Is Nothing Then
xlapp.Visible = True
xlapp.Application.quit
Set xlapp = Nothing
End If
Unload Me
Else
MsgBox "プログラムが既に起動されています!", vbInformation, "売上管理システム"
Unload Me
End If
End Sub
Here is my code in excel file when close the userform
Application.DisplayAlerts = False
ThisWorkbook.Close False
Application.Visible = True
Application.Quit
End
I really need to solve this problem in this week, any solution?
Thank you guys in advance and please pardon for my english
Here is some images. I hope they will help you guys to understand my problem
This happens when I use Thisworkbook.close False statement:
This happens when I dont use Thisworkbook.close False statement:
Inside this file, there is an userform that gonna be automatically opened when the file is opened.
when I close my userform (I do have codes to close workbook, quit excel app when the userform is closed).
You are doing this incorrectly. Do not close/quit it from the UserForm. Do it from VB6 form. This way, vb6 will be able to handle and clear the objects.
Here, try this (I already tried it and it works...). This will not leave an instance of Excel running. I have commented the code. But if you still have questions then simply ask.
Note: Before you try this (Just for testing purpose), close all Excel application. Even from the task manager.
Private Sub Form_Load()
Dim oXLApp As Object
Dim oXLWb As Object
Dim ICreateatedExcel As Boolean
'~~> Establish an EXCEL application object
On Error Resume Next
Set oXLApp = GetObject(, "Excel.Application")
'~~> If not found then create new instance
If Err.Number <> 0 Then
Set oXLApp = CreateObject("Excel.Application")
'~~> I created instance of Excel
ICreateatedExcel = True
End If
Err.Clear
On Error GoTo 0
'~~> Check if you have an instance of Excel
If oXLApp Is Nothing Then
MsgBox "Unable to get an instance of Excel.", vbCritical, "Excel is Installed?"
Exit Sub
End If
Me.Hide
'~~> Show Excel
oXLApp.Visible = True
'~~> Open file
Set oXLWb = oXLApp.Workbooks.Open("C:\Tester.xlsm")
'~~> This and other lines below will not run till the
'~~> time you close the userform in Excel
'~~> Close the workbook
oXLWb.Close (False) '<~~ Set this to True if you want to save changes
Set oXLWb = Nothing
'~~> If I created Excel then quit
If ICreateatedExcel = True Then oXLApp.Quit
Set oXLApp = Nothing
Unload Me
End Sub
I am using VBA to open the open PowerPoint chart data in Excel and perform a series of actions, such as hiding/deleting rows & columns. I am using the chart.ChartData.Activate command to open the Excel. I had issues in the past with trying to close the workbook immediately after processing, using Workbook.Close(), so I left the Excels open. This has now become an issue with larger presentations and it's causing PowerPoint to crash and open back up in Recovery Mode. Even when I reinstate the Workbook.Close() command, sometimes these instances of Excel still remain open or I lose scope to them inside the routine.
I am processing the presentation on a slide by slide basis so I'm looking for a way to close these open instances all at once, after I'm done processing each slide.
Does anyone know how to access these hanging Excel processes? I've included a picture to better help explain where they reside.
I created an example routine below. I am using the ChartData.ActivateChartDataWindow command instead ChartData.Activate b/c when originally designing this, the Activate command caused the full Excel application to open instead of the ChartDataWindow and tremendously slowed down processing and would sometimes crash when repeated over and over again.
I also added an image of PowerPoint with the ChartDataWindows that are left open by my code.
Private Sub ClearColumnsInExcel()
'Set the slide
Dim slide As slide
Set slide = pptPres.Slides(1)
'Index through each shape on the slide
Dim shapeX As Integer
For shapeX = 1 To slide.Shapes.Count
'If this shape has a chart
If slide.Shapes(shapeX).Type = msoChart Then
'Set the chart
Dim chart As chart
Set chart = slide.Shapes(shapeX).chart
'Set the worksheet
Dim wks As Worksheet
Set wks = chart.ChartData.Workbook.Worksheets(1)
'Activate the workbook
chart.ChartData.ActivateChartDataWindow
'Clear target columns
'Remove objects from memomry
Set wks = Nothing
Set chart = Nothing
End If
Next shapeX
End Sub
I am not sure how you build you code, but you are just closing the workbook. To get the desired outcome, you need to quit the excel application.
I think something like this you do the trick:
Private Sub testSave()
Dim xlsApp As Excel.Application
Dim xlsWbk As Excel.Workbooks
Set xlsApp = New Excel.Application
xlsApp.Visible = True
Set xlswkb = xlsApp.Workbooks.Add 'creating a new wokbook just to test
'do your thing here
xlswkb.Close SaveChanges:=False ' close workbook without saving in this
example
xlsApp.Quit ' quitting the excel app
End Sub
I want to close the active macro workbook inside the Userform_Terminate event. The problem I am facing is that, a ghost window of excel application lingers on even after workbook has been closed.
Have tried most of the suggested ways, I could get my hands on (described in detail in the code snippet) but to no avail. If anybody can help, much grateful.
NOTE: Have released almost all excel related objects from memory by setting it to nothing.
Code :
Private Sub UserForm_Terminate()
' Application.DisplayAlerts = False ' The excel ghost window lingers on
' ThisWorkbook.Close , False
' Application.DisplayAlerts = True
'
' Application.DisplayAlerts = False ' The excel ghost window lingers on
' ThisWorkbook.Saved = True
' ThisWorkbook.Close , False
' Application.DisplayAlerts = True
' Application.DisplayAlerts = False 'The excel ghost window lingers on.
' ThisWorkbook.Close , False
' Application.Quit
' Application.DisplayAlerts = True
Application.DisplayAlerts = False 'Ghost window is closed but also kills all instances of excel currently open
Application.Quit
Application.DisplayAlerts = True
'NOTE:
'Have released all excel related objects from memory by setting it to nothing, post use.
End Sub
Snap:
Well, your "gost" problem has the next explanation:
An Excel session/instance means the same Application handler. If you open a workbook from the Excel existing interface, it is open in the same instance. Pressing Ctrl + F6 will jump to the next workbook open in the same instance...
If there are open workbooks not seen in the Ctrl + F6 sequence, this only means that they are open in a different instance.
Another instance is open, for instance :), in this way:
Din ExApp as Object
Set ExApp = CreateObject("Excel.Application")
ExApp.Workbooks.add 'without this line, the instance is quit by itself...
Set ExApp = Nothing 'this only releases the memory
You can see more open Excel instances (if they exist) looking in TaskManager and seeing more the one such application (Excel.exe)...
When you close a workbook, and this specific workbook is the single one of the instance, the application Window, what you name a "gost" remains!. If there are some other workbooks open, the so named "gost" window disappears, too.
In order to handle both situations, please try the next approach:
Private Sub UserForm_Terminate()
If Workbooks.Count > OpenWb Then
ThisWorkbook.Close , False
Else
Application.Quit
End If
End Sub
Function OpenWb() As Long
Dim count As Long, wb As Workbook, arr
For Each wb In Workbooks
arr = Split(wb.Name, ".")
If UCase(arr(UBound(arr))) = "XLSB" Then count = count + 1
Next
OpenWb = count + 1
End Function
Quitting the application is done here only because you asked for it... When you try programmatically to open and close many workbooks, it is more efficient to keep the application open. To open a new instance takes time. To open a workbook in an existing instance takes less time... But to do that, your code must find that existing instance:
Sub testExcelInstance()
Dim Ex As Object
On Error Resume Next
Set Ex = GetObject(, "Excel.Application")
If Ex Is Nothing Then
Err.Clear: On Error GoTo 0
Set Ex = CreateObject("Excel.Application")
End If
On Error GoTo 0
Ex.Workbooks.Add 'just doing something after having the Excel instance object
End Sub
Releasing the objects from the memory does not do anything, in terms of the object itself existence. If physically disappears only if you quit it.
I am trying to write a macro in Word so that I can save some information into an Excel file somewhere else in my computer. For this reason I wrote this:
Dim exlApp As Object
Dim exlWbk As Object
Set exlApp = CreateObject("Excel.Application")
Set exlWbk = exlApp.Workbooks.Open(FileName:="D:\database.xlsx")
exlWbk.ActiveSheet.Cells(1, 1).Value = "some info"
exlWbk.Close SaveChanges:=True
Set exlWbk = Nothing
exlApp.Quit
Set exlApp = Nothing
The code works perfectly fine for me, except when the Excel file in question (database.xlsx) is already opened by the user. In that case, running the macro will prompt me to save the new changes into a new copy of my excel file, which is not what I want. I want the new changes to be included in the current Excel file without creating a second copy of it.
Since the above code presented some problems, I wrote this:
Dim exlApp As Object
Dim exlWbk As Object
Set exlApp = CreateObject("Excel.Application")
Set exlWbk = exlApp.GetObject("D:\database.xlsx")
exlWbk.ActiveSheet.Cells(1, 1).Value = "some info"
exlWbk.Save
Set exlWbk = Nothing
exlApp.Quit
Set exlApp = Nothing
But nothing changed. I know there are some ways to figure out whether my Excel file is open or not, but the problem is that I don't know how to change my code if I find out that file is open.
How can I determine whether a workbook is open in Excel so that it can be edited, or open the file in order to edit it if it's closed?
According to the documentation, GetObject(filename) will pick up the existing file if it's already open or, optionally, open the file if it is not open:
When this code is executed, the application associated with the
specified pathname is started, and the object in the specified file is
activated.
If Excel is not running, by default nothing will be visible when GetObject(filename) executes. Excel will be opened, the file will be opened and changed. There's a real danger, therefore, that the instance of Excel and the workbook will "hang" in memory, which could be seen in the Windows "Task Manager". Repeated running of such code can eventually crash Windows, so care must be taken to clean things up correctly on each iteration.
Since the question also stipulates that the file could be opened already by a user, it's necessary to determine that, as well as whether the Excel application is already running.
The following code sample demonstrates how this can be done. The assumption is that neither the applicaton nor the file is open. Then it tests whether Excel is already running.
Set xlApp = GetObject(, "Excel.Application")
Notice the difference in the syntax: instead of the fileName there's a comma, followed by the name of the application. This will check whether the application is available; if it's not, an error will be triggered. Therefore, On Error Resume Next precedes GetObject, which means the error will be ignored.
Since ignoring errors is dangerous, the next line Or Error GoTo 0 turns errors back on.
If GetObject is not successful, the variable xlApp could not be instantiated and its "value" is Nothing. If Not xlApp Is Nothing executes if xlApp could be instantiated and the Boolean appAlreadyOpen is set to true so that we know to not quit Excel when the code finishes. It also checks whether the required workbook is already open. If it is, xlWb can be instantiated and fileAlreadyOpened set to true.
If xlWb could not be instantiated, either because the Excel application was not running or the workbook was not yet open, GetObject(fileName) is executed. The workbook will be opened, in the existing instance of Excel if already running or in a new instance of Excel. At the end of this code block two lines are commented: should the newly started Excel application be made visible and remain open when the code ends, uncomment them.
The workbook can then be edited.
Lastly, things need to be cleaned up. The Booleans are checked and if not true, the workbook and possibly the application are closed. Very important are the last two lines that release these objects from memory. If the code creates any other objects, such as Ranges, these should also be released, in the reverse order they are instantiated.
Sub GetFileOpenedOrClosed()
Dim xlApp As Object ' Excel.Application
Dim xlWB As Object, wb As Object ' Excel.Workbook
Dim fileName As String
Dim fileAlreadyOpen As Boolean, appAlreadyOpen As Boolean
fileName = "C:\Test\SampleChart.xlsx"
fileAlreadyOpen = False
appAlreadyOpen = False
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
On Error GoTo 0
If Not xlApp Is Nothing Then
appAlreadyOpen = True
For Each wb In xlApp.Workbooks
If wb.FullName = fileName Then
Set xlWB = wb
fileAlreadyOpen = True
Exit For
End If
Next
End If
If xlWB Is Nothing Then
Set xlWB = GetObject(fileName)
Set xlApp = xlWB.Application
xlWB.Windows(1).Visible = True 'So that the window is not hidden when file is opened again
'xlApp.Visible = True
'xlApp.UserControl = True
End If
xlWB.Worksheets(1).Cells(7, 1).value = "some other info"
If Not fileAlreadyOpen Then
xlWB.Save
xlWB.Close
End If
If Not appAlreadyOpen Then
xlApp.Quit
End If
Set xlWB = Nothing
Set xlApp = Nothing
End Sub
My problem is quite simple but I haven't found a solution so far...
I created a form in Access called Form1.
In this form, I inserted an "Unbound Object Frame", which is a new macro-enabled Excel worksheet.
In the Excel sheet, I create a macro we can call "ExcelMacro".
I want to know how to run macros in this Excel sheet from Access, e.g. in my Access macro, run "ExcelMacro"
I do NOT want to link my Excel sheet to an external Excel workbook.
Do you have any ideas?
Thanks a lot for your help!
Edit:
In case you need some additional information:
Name of Unbound Object Frame: xlObject
OLE Class: Microsoft Excel Macro-Enabled 12
Class: Excel.SheetMacroEnabled.12
Sheet name: Sheet1
You can use the following in Access:
Public Sub RunExcelMacro()
Dim excelApp As Object
Set excelApp = GetObject(, "Excel.Application")
excelApp.Run "HelloWorld"
End Sub
Where "HelloWorld" is the name of the Excel Macro.
GetObject(, "Excel.Application") gets the latest opened Excel application. This needs to be the Excel application that is running your embedded worksheet. If it's another, it will fail.
Also, the worksheet needs to be open, else it will fail (you can add either of the following code segments to open it before running this).
Me.MyOLEUnbound.Verb = 0 'vbOLEPrimary
Me.MyOLEUnbound.Action = 7
or
Me.MyOLEUnbound.AutoActivate = 1 'vbOLEActivateGetFocus
Me.MyOLEUnbound.SetFocus
To make sure there are no other instances of Excel running, and possibly quit them if they are (note: these make use of runtime errors and error handlers)
Public Function IsExcelRunning() As Boolean
IsExcelRunning = True
On Error GoTo ReturnFalse:
Dim obj As Object
Set obj = GetObject(, "Excel.Application")
Exit Function
ReturnFalse:
IsExcelRunning = False
End Function
Public Sub CloseAllExcel()
Dim obj As Object
On Error GoTo ExitSub
Dim i As Integer
'There shouldn't be more than 10000 running Excel applications
'Can use While True too, but small risk of infinite loop
For i = 0 To 10000
Set obj = GetObject(, "Excel.Application")
obj.Quit
Next i
ExitSub:
End Sub