Как поймать Exception в vba-коде, работающем на python - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть макрос VBA, который работает на Python,

, если макрос не удается, как я могу поймать его в Python?в настоящее время он зависает и будет ждать ответа пользователя.Как я могу обойти это?я не могу использовать On Error GoTo 0, так как я понятия не имею, VBA успешно завершена или нет.

import win32com.client
xl=win32com.client.Dispatch("Excel.Application")
xl.Workbooks.Open("/myexceldirectory/excel.xlsm")

try:
    xl.Application.Run("excel.xlsm!mymacro.mymacro")
except Exception as e:
    print("i failed {}".format(e))

1 Ответ

0 голосов
/ 09 июля 2019

Не уверен, что это оптимальный способ сделать это, но он работает.

Идея такова:

  1. Создать временный класс, который обернет макрос, который вы намереваетесьcall.
  2. Создать функцию, которая создает экземпляр временного класса
  3. Вызвать вновь созданную функцию

Затем Python может зафиксировать любую ошибку, которую выдает этот класс.

ПРИМЕЧАНИЕ: Макрос все еще может зависнуть, если у макроса есть всплывающее окно MsgBox

from win32com import client as win32client

import clr
clr.AddReference('Microsoft.Vbe.Interop, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c')
clr.AddReference('Microsoft.VisualBasic')
from Microsoft.Vbe.Interop import vbext_ComponentType

def run_macro(xl, wb, sheetname, macro_name):
    # Dynamically add VBA class to workbook
    f = wb.VBProject.VBComponents.Add(vbext_ComponentType.vbext_ct_ClassModule)

    # Avoid duplicate names
    tempGuid = str(uuid.uuid4())[:8]

    f.Properties.Item("Instancing").Value = 2
    f.Name = "CLS_" + tempGuid
    f.CodeModule.AddFromString(
        "Public Sub TempClassCall()\r\n" +
        "   Call " + macro_name +
        "\r\n" +
        "End Sub\r\n")

    # Dynamically add VBA module to create dynamic VBA class
    f2 = wb.VBProject.VBComponents.Add(vbext_ComponentType.vbext_ct_StdModule)
    f2.Name = "MOD_" + tempGuid
    f2.CodeModule.AddFromString(
        "Public Function instantiateTempClass_{0}() As Object\r\n    Set instantiateTempClass_{0} = New CLS_{0}\r\nEnd Function".format(tempGuid))

    try:
        wb.Activate()
        tempObject = xl.Run(sheetname + "!instantiateTempClass_{}".format(tempGuid))
        tempObject.TempClassCall()
    except com_error as e:
        raise e
    finally:
        self._wb.VBProject.VBComponents.Remove(f)
        self._wb.VBProject.VBComponents.Remove(f2)
...