使用 win32com.client 将 xls 重新保存为 xlsx 时如何 disable/autoanswer 关于 macros/VB 项目的对话框?

How to disable/autoanswer dialog box about macros/VB Project when resaving xls to xlsx with win32com.client?

使用此代码时:

import win32com.client as win32

input_files = os.listdir(parent_dir)
input_files = [parent_dir + i for i in input_files if i.endswith('.xls') and not i.endswith('.xlsx')]
for input_file in input_files:
    if not os.path.isfile(input_file.replace('.xls', '.xlsx')):
        excel = win32.gencache.EnsureDispatch('Excel.Application')
        wb = excel.Workbooks.Open(input_file)
        wb.SaveAs(input_file + "x", FileFormat=51)  # FileFormat = 51 is for .xlsx extension
        wb.Close()  # FileFormat = 56 is for .xls extension
        excel.Application.Quit()

在包含一些 macros/VB 项目的 excel 文件上,消息框经常显示警告,所有 macros/VB 项目都将丢失,我想以某种方式自动回答它,例如,"Yes",或者可能有一些 SaveAs 函数的参数或

的设置

win32.gencache.EnsureDispatch('Excel.Application')?

现在我可以使用 FileFormat=51 将文件重新保存为 xlsm,但出于某些安全原因我不想这样做,我的文件中真的不需要这个 macros/VB 项目。

已尝试 excel.DisplayAlerts = 错误 - 没有帮助。

也在考虑像 pywinauto 这样的东西,但也许它有点过头了,也许还有更优雅的解决方案?

使用

wb.Close(True) #if you need to save .xls file also

或使用

wb.Close(False) # if you not decide to save .xls file

另一方面,它可能打开了其他文件,因此当您使用 excel.Application.Quit() 并且这些文件未保存时,excel 将在关闭前显示确认对话框。

嗯,有趣的是,如果你保存在xlsm中,而不是在xlsx中,Excel不会问包含macros/VB项目的问题,你可以像xlsm一样在openpyxl中打开xlsm,所以, 如何在 xlsm 中重新保存:

def resave_xls_file_as_xlsx_or_xlsm(in_xls_file_path, out_excel_file_type='xlsm'):
    excel = win32.gencache.EnsureDispatch('Excel.Application')
    wbxls = excel.Workbooks.Open(in_xls_file_path)
    in_xls_file_path = in_xls_file_path.replace('/', '\')
    out_xlsx_or_xlsm_file_path = in_xls_file_path + out_excel_file_type[-1]
    # FileFormat = 51 is for .xlsx extension, 52 for xlsm, no questions about containing VB script for xlsm
    if out_excel_file_type == 'xlsm':
        excel_file_format = 52
    elif out_excel_file_type == 'xlsx':
        excel_file_format = 51
    else:
        excel_file_format = 52  # or do some error corrections:
        # print('ERROR, wrong excel file type:', out_excel_file_type)
        # return None # sys.exit ('taihen taihen') # raise cthulhu
    wbxls.SaveAs(out_xlsx_or_xlsm_file_path, FileFormat=excel_file_format)
    wbxls.Close()
    excel.Application.Quit()
    return out_xlsx_or_xlsm_file_path

此外,有时我们有某种损坏的 xlsx 文件,Excel 开始抱怨它,然后脚本停止,要自动恢复它,您可以使用此代码,注意 xlsx 文件路径,因为例如,此路径在这种情况下不起作用:

resaved_xlsx_on_disk = 'c:/this_wont_work/2.xlsx' # 通常有效,但不适用于 win32.client

corrupted_xlsx_on_disk = 'c:\fyi_if_you_dont_use_two_backslashes_and_use_slashes_in_path_it_will_not_open\1.xlsx'
resaved_xlsx_on_disk = r'c:\you_can_also_use_this.xlsx'
xl = win32.gencache.EnsureDispatch('Excel.Application')
# xl.Visible = True # otherwise excel is hidden (btw if corrupted it anyway show some message, but autoclose it)
wb = xl.Workbooks.Open(corrupted_xlsx_on_disk, CorruptLoad=1)
xl.SendKeys("{Enter}", Wait=1)
xl.DisplayAlerts = 0
wb.SaveAs(resaved_xlsx_on_disk)  # You can try wb.Save(), but I can't get it to work :-(
wb.Close()
xl.Application.Quit()

=== 更新。 2021 年 8 月 9 日: 考虑到上面的代码,当使用相反的操作 - 将 xlsx 重新保存到 xls 时,经常 windows 发生兼容性检查(另外,如果 Excel 看起来像挂断 - 这可能是因为 window 确实没有获得焦点并隐藏在其他 windows) 之间,tl;dr,excel.DisplayAlerts = False 完成工作,代码示例(我也会检查,也许它适用于不使用此 xlsm 扩展的 xls->xlsx 转换, 如果 xls 包含宏):

import os
import win32com.client
import win32com

# if strange errors on start occures, delete everything from this path
# (maybe dynamic loading from now do this action unnecessary):
print(win32com.__gen_path__)


def resave_xlsx_files_as_xls(files_parent_dir):
    input_files = os.listdir(files_parent_dir)  # todo: use the glob, Luke!
    input_files = [files_parent_dir + i for i in input_files if i.endswith('.xlsx')]
    for input_file in input_files:
        print(input_file)
        if not os.path.isfile(input_file.replace('.xlsx', '.xls')):
            excel = win32com.client.dynamic.Dispatch('Excel.Application')
            wbxls = excel.Workbooks.Open(input_file)
            # wbxls.DoNotPromptForConvert = True # seems that this line has no effect if uncommented
            # wbxls.CheckCompatibility = False # seems that this line also has no effect if uncommented
            excel.DisplayAlerts = False  # this line do the main job - compatibility check window did not shows up!
            # AFAIK this library hardly understand normal os.path.join or os.path.sep
            input_file = input_file.replace('/', '\')
            input_file = input_file.replace('.xlsx', '.xls')
            # FileFormat = 51 is for .xlsx extension, 52 for xlsm
            excel_file_format = 56
            # Compatibility check window will show up here on SaveAs line, you may did not locate it at first, cause it
            # usually don't get focus, so it may be hidden somewhere under couple of windows, best
            # way to find it - click "-" button on every window until wallpaper shows up, pressing
            # hotkeys like Win-D will not help - this command will hide this compatibility check
            # window also
            wbxls.SaveAs(input_file, FileFormat=excel_file_format)
            wbxls.Close()  # FileFormat = 56 is for .xls extension
            excel.Application.Quit()
        else:
            print('There is already converted file in folder!')

    output_files = os.listdir(files_parent_dir)
    output_files = [files_parent_dir + i for i in output_files if i.endswith('.xls')]
    return output_files


resave_xlsx_files_as_xls('c:/test/')