ニッチすぎるけど、xlwingsでExcelインスタンスを生成するときの問題点とその解決方法を紹介。
0. 環境
以下で確認しています。
- OS: Windows 10 (1809)
- Office 2016
- xlwings 0.20.7
1. 問題点
xlwingsでExcelインスタンスを生成するには、 xw.apps.add()
や xw.App()
を使用する。しかし、この方法の場合、以下の問題点がある。
- なぜかアドインが読み込まれない。
- そのインスタンを閉じた後、エクスプローラーからブックを開いてもアドインが読み込まれない。
- まれに
pywintypes.com_error
エラーが発生(しかもtry exceptで制御不可)
なお、ブックを開かずにExcelだけを開けば(スタートメニューから起動)、アドインは正常に読み込まれるようになる。
2. 解決方法
xw.apps.add()
や xw.App()
を使わずに、シェルからExcelインスタンスを生成し、xlwingsに渡す。
from pathlib import Path
import re
import subprocess
import time
import winreg
import xlwings as xw
def get_path_to_xl() -> Path:
path = r'SOFTWARE\MICROSOFT\Windows\CurrentVersion\App Paths\Excel.exe'
key = winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, path)
data, _ = winreg.QueryValueEx(key, 'Path')
return Path(rf'{data}\EXCEL.EXE')
def get_path_to_xl2() -> Path:
#Excelのインストール先パスを返す関数
subprocess_rtn = (
subprocess
.run(['assoc','.xlsx'], shell=True, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
.stdout.decode("utf8")
)
assoc_to = re.search('Excel.Sheet.[0-9]+', subprocess_rtn).group()
subprocess_rtn = (
subprocess
.run(['ftype', assoc_to], shell=True, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
.stdout.decode('utf-8')
)
xl_path = re.search('C:.*EXCEL.EXE', subprocess_rtn).group()
return Path(xl_path)
def add_xl_app(add_book: bool=True) -> xw.App:
command = f'"{str(get_path_to_xl())}" /x /e'
proc = subprocess.Popen(command)
while True:
try:
xl_app = xw.apps[proc.pid]
break
except:
time.sleep(0.5)
if add_book:
xl_app.books.add()
return xl_app
app = add_xl_app()