问题
I'm trying to figure out how to close an Excel instance properly if the Python console program is interrupted and closed while executing.
Below is a minimal reproducible example:
# import pythoncom
import traceback
import win32com.client
import win32api
def exit_handler(arg):
file = open('Log.txt', 'w')
file.write(f'{repr(workbook)}\n{repr(excel_application)}\n')
try:
# pythoncom.CoInitialize()
workbook.Close(SaveChanges=False)
excel_application.Quit()
except Exception:
file.write(traceback.format_exc())
finally:
file.close()
excel_application = win32com.client.DispatchEx(clsid='Excel.Application')
workbook = excel_application.Workbooks.Add()
win32api.SetConsoleCtrlHandler(exit_handler, True)
input('Don\'t press the "Enter" key.\nClose the console by clicking the top right "X" button or by pressing the "Alt" + "F4" keys.\n')
# The input is just to pause the program for the user to close the console before it finishes executing. If it does finish executing the function exit_handler won't run.
I'm handling the exit event in the function exit_handler
which is set by win32api.SetConsoleCtrlHandler
and runs if the console is closed by the user.
I can execute workbook.Close(SaveChanges=False)
and excel_application.Quit()
outside of the function without any problem when the console isn't being closed but when I run it inside I get an error/exception.
The resulting Log.txt
file gets the following content:
<win32com.gen_py.None.Workbook>
<win32com.gen_py.Microsoft Excel 15.0 Object Library._Application instance at 0x10283920>
Traceback (most recent call last):
File "PathCensored\Excel.py", line 9, in exit_handler
workbook.Close(SaveChanges=False)
File "C:\Users\UserNameCensored\AppData\Local\Temp\gen_py\3.7\00020813-0000-0000-C000-000000000046x0x1x8\_Workbook.py", line 71, in Close
, Filename, RouteWorkbook)
pywintypes.com_error: (-2147221008, 'CoInitialize has not been called.', None, None)
If I uncomment the import pythoncom
and pythoncom.CoInitialize()
lines in their respective place the Log.txt
file gets the following content instead:
<win32com.gen_py.None.Workbook>
<win32com.gen_py.Microsoft Excel 15.0 Object Library._Application instance at 0x44609616>
Traceback (most recent call last):
File "PathCensored\Excel.py", line 11, in exit_handler
workbook.Close(SaveChanges=False)
File "C:\Users\UserNameCensored\AppData\Local\Temp\gen_py\3.7\00020813-0000-0000-C000-000000000046x0x1x8\_Workbook.py", line 71, in Close
, Filename, RouteWorkbook)
pywintypes.com_error: (-2147417842, 'The application called an interface that was marshalled for a different thread.', None, None)
The Close
function in the file C:\Users\UserNameCensored\AppData\Local\Temp\gen_py\3.7\00020813-0000-0000-C000-000000000046x0x1x8\_Workbook.py
is:
def Close(self, SaveChanges=defaultNamedOptArg, Filename=defaultNamedOptArg, RouteWorkbook=defaultNamedOptArg):
return self._oleobj_.InvokeTypes(277, LCID, 1, (24, 0), ((12, 17), (12, 17), (12, 17)),SaveChanges
, Filename, RouteWorkbook)
Related questions that I have checked to try to find a solution:
Python - Windows Shutdown Events
python3 ctype CreateWindowEx simple example
Python - How to detect when user closes a console application via “X” button
How do i catch system Logoff/ShutDown/Lock events in Python or PyQt4
Python Save Sets To File On Windows Shutdown?
Using win32com with multithreading
How to handle console exit and object destruction
Python, How to close excel workbook if user prematurely closes the command prompt?
来源:https://stackoverflow.com/questions/63037454/how-to-close-an-excel-instance-if-the-python-console-program-gets-interrupted-an