Currently I try to cancel Excel's close event using Python and win32com. I have already managed to handle this issue with IronPython some month ago. But for further purposes of my companies department this should also be able with Python. Followed you will see two snippets. The first will contain the working IronPython Code
import clr
clr.AddReference("Microsoft.Office.Interop.Excel")
clr.AddReference("System.Windows.Forms")
from Microsoft.Office.Interop import Excel
from System.Windows.Forms import Form, Application, MessageBox, MessageBoxButtons, MessageBoxIcon, DialogResult
class CloseEventTry(Form):
def __init__(self):
excel = Excel.ApplicationClass()
excel.Visible = True
excel.DisplayAlerts = False
self.workbooks = excel.Workbooks.Add()
self.Text = "Dummy GUI Window"
#link "BeforeCloseEvent" to the "beforeClose" method
self.workbooks.BeforeClose +=Excel.WorkbookEvents_BeforeCloseEventHandler(self.beforeClose)
def beforeClose(self, cancel):
print type(cancel) #Type: 'StrongBox[bool]
choice = MessageBox.Show("Close Excel", "Close", MessageBoxButtons.YesNo, MessageBoxIcon.Information)
if choice == DialogResult.Yes:
cancel.Value = False #do't cancel the close action
self.Close()
elif choice == DialogResult.No:
cancel.Value = True #prevent excel from closing
Application.Run(CloseEventTry())
The second one will contain the version with Python and win32com. This one is based on my IronPython snippet and the sample of that link
https://win32com.goermezer.de/microsoft/office/events-in-microsoft-word-and-excel.html
import clr
clr.AddReference("System.Windows.Forms")
from System.Windows.Forms import Form, Application, MessageBox, MessageBoxButtons, MessageBoxIcon, DialogResult
import win32com.client as win32
#workbook event handler class. Needed according to this example https://win32com.goermezer.de/microsoft/office/events-in-microsoft-word-and-excel.html
class WorkBookEvents(object):
def OnBeforeClose(self, cancel):
print(type(cancel)) #Type: class 'bool'
choice = MessageBox.Show("Close Excel", "Close", MessageBoxButtons.YesNo, MessageBoxIcon.Information)
if choice == DialogResult.Yes:
#do't cancel the close action => raises AttributeError: 'bool' object has no attribute 'Value' Exception
cancel.Value = False
self.Close()
elif choice == DialogResult.No:
#prevent excel from closing => raises AttributeError: 'bool' object has no attribute 'Value' Exception
cancel.Value = True
class CloseEventTry(Form):
def __init__(self):
excel = win32.DispatchEx('Excel.Application')
excel.Visible = True # makes the Excel application visible to the user
excel.DisplayAlerts = False
self.Text = "Dummy GUI Window"
self.workbooks = excel.Workbooks.Add()
#define event handler according to this example https://win32com.goermezer.de/microsoft/office/events-in-microsoft-word-and-excel.html
self.workbooks = win32.DispatchWithEvents(self.workbooks, WorkBookEvents)
Application.Run(CloseEventTry())
As you will see I could connect to the "OnBeforeClose" event, but cannot cancel the close event as I've done it with the IronPython version. As mentioned in the last code snippet's comment, the Python version raises an AttributeError exception. Further you can also see, that the types of the needed "cancel" variable of the event handlers have two different types. In the IronPython version its a "StrongBox[bool]". On the other hand the Python version's type is a common "class 'bool'" type (which explains the exception). Thats way I tried to just type
cancel = True #prevent excel from closing
But using this way, excel closes anyway. I also did some research but was not able to find a solution for this issue. My Assumption is that there is some kind of wrapper needed?
you can achieve the same behaviour as the IronPython version by returning the desired cancel value, e.g.
return True
in case you want to abort the Close event.
Regards