Не удается полностью закрыть Excel с помощью win32com на Python

Это мой код, и я нашел много ответов для VBA, платформы .NET, и это довольно странно. Когда я выполняю это, Excel закрывается.

from win32com.client import DispatchEx
excel = DispatchEx('Excel.Application')
wbs = excel.Workbooks
wbs.Close()
excel.Quit()
wbs = None
excel = None # <-- Excel Closes here

Но когда я делаю следующее, он не закрывается.

excel = DispatchEx('Excel.Application')
wbs = excel.Workbooks
wb = wbs.Open('D:\\Xaguar\\A1.xlsm')
wb.Close(False)
wbs.Close()
excel.Quit()
wb = None
wbs = None
excel = None  # <-- NOT Closing !!!

Я нашел возможный ответ в вопросе о переполнении стека Процесс Excel остается открытым после взаимодействия; традиционный метод не работает. Проблема в том, что это не Python, и я не нахожу Marshal.ReleaseComObject и GC. Просмотрел все демки на ...site-packages/win32com и других.

Даже меня не смущает, если я могу просто получить PID и убить его.

Я нашел обходной путь в Убить процесс по имени окна (win32).

Может быть, это неправильный способ, но обходной путь:

def close_excel_by_force(excel):
    import win32process
    import win32gui
    import win32api
    import win32con

    # Get the window's process id's
    hwnd = excel.Hwnd
    t, p = win32process.GetWindowThreadProcessId(hwnd)
    # Ask window nicely to close
    win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
    # Allow some time for app to close
    time.sleep(10)
    # If the application didn't close, force close
    try:
        handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0, p)
        if handle:
            win32api.TerminateProcess(handle, 0)
            win32api.CloseHandle(handle)
    except:
        pass

excel = DispatchEx('Excel.Application')
wbs = excel.Workbooks
wb = wbs.Open('D:\\Xaguar\\A1.xlsm')
wb.Close(False)
wbs.Close()
excel.Quit()
wb = None
wbs = None
close_excel_by_force(excel) # <--- YOU #@#$# DIEEEEE!! DIEEEE!!!

person sacabuche    schedule 19.04.2012    source источник
comment
Попробуйте добавить строку excel.DisplayAlerts = False перед вызовом wbs.Open(...) и посмотрите, поможет ли это.   -  person srgerg    schedule 19.04.2012
comment
:/ не работает, это настоящая боль excel и COM   -  person sacabuche    schedule 19.04.2012
comment
Я нахожу способ, но не использую COM   -  person sacabuche    schedule 19.04.2012
comment
Более быстрый, чистый и простой ответ здесь: stackoverflow.com/a/18421814   -  person Tom    schedule 08.02.2018


Ответы (5)


Попробуй это:

wbs.Close()
excel.Quit()
del excel # this line removed it from task manager in my case
person ROJI    schedule 18.11.2013
comment
del excel не удаляет процесс Excel из диспетчера задач - person Heetola; 26.05.2015
comment
Попробуйте изменить wbs.Close() на wbs.Close(False), чтобы закрыть книгу без сохранения. - person Jonathan Kunze; 31.03.2017

У меня есть это в моих файлах, которые используют Excel:

self.excel.Application.Quit()
person Aaron S    schedule 07.08.2012
comment
и вы используете DispatchEx или Dispatch, и он действительно закрывается или продолжает работать? потому что на самом деле, когда я закрываю, он кажется закрытым, но он остается живым, когда я вижу диспетчер задач - person sacabuche; 08.08.2012
comment
Ой извините за это. Я использую SureDispatch, что может иметь значение. После этого он полностью закрыт. - person Aaron S; 08.08.2012

Что сработало для меня, так это убедиться, что все переменные, которые вы назначили по пути, разыменовываются следующим образом:

import win32com.client as win32

fileDirectory = 'Hello World.xlsx'

#excelFile = win32.Dispatch('Excel.Application')
excelFile = win32.gencache.EnsureDispatch('Excel.Application')

excelFile.Visible = True
excelFile.DisplayAlerts = True

wb = excelFile.Workbooks.Open(fileDirectory)
ws = wb.Sheets("Sell")

ws.Range("D1").Value = "Hello World!"
ws = None

wb.Close(False)
wb = None

excelFile.Quit()
excelFile = None

Он работал с любым форматом Dispatch.

person Robert Criqui    schedule 19.08.2020

Python должен обрабатывать жизненный цикл COM-объекта. Просто установите excel = None. См. это для справки:

# CH9 says: Python manages COM lifetimes automatically for you; when your excel 
#           variable is no longer used, Excel automatically closes. In Python,
#           the simplest way to remove this variable is to assign it to another 
#           value. If you use the following code, notice that Excel vanishes 
#           from the screen; it knows there are no longer any programs referring to it. 

источник:

http://www.icodeguru.com/WebServer/Python-Programming-on-Win32/ch05.htm#:%7E:text=xl%20=%20None

person LeanMan    schedule 09.09.2020

Мне понравилось, что уничтожение процесса Excel через win32com не всегда так надежно. К ним относятся excel.Application.Quit() и del excel, как было предложено выше.

Я обнаружил, что единственный способ убедиться, что он мертв, — это физически убить процесс EXCEL.EXE:

import psutil

def kill_excel():
    for proc in psutil.process_iter():
        if proc.name() == "EXCEL.EXE":
            proc.kill()

Недостатком является то, что этот скрипт, очевидно, убьет все запущенные в данный момент процессы Excel. ЕСЛИ с этим можно жить, то это не плохой вариант.

person Paul    schedule 01.04.2021