以Windows服务方式运行Excel自动化程序遇到的问题与解决方法

发布于:2019-09-14 | 分类:process automation


参考前文关于win32com模块的示例代码可以进行Excel的自动化操作,例如Excel VBA的自动化测试;将其作为Windows服务运行,则可以方便为网络中的其他机器调用。本文正是记录配置Excel自动化服务过程中遇到的问题与相应解决措施。

概述

最近有个需求是对启用宏的Excel 2010文件的自动化测试,需要配置在服务器上以供GitLab-Runner调用。于是,按照读入测试数据、执行测试VBA、验证计算结果的逻辑写好Python脚本,调试通过后在本地运行一切正常。然而,通过Commit提交触发CI/CD流程,即GitLab-Runner以Windows服务的方式执行相同的脚本时,却出现了各种各样的问题。

根本原因显然是 本地账户系统服务 执行Excel自动化操作上的差异,以下逐一记录遇到的问题。除了部分与Python相关的问题外,其余应该具备通用性,可作为Windows服务方式执行Excel、Word、Outlook等自动化程序出现问题时的参考。

注意

当前登陆账户应具备管理员权限。

Open method of Workbooks class failed

(-2147352567, 'Exception occurred.', 
(0, 'Microsoft Excel', 'Open method of Workbooks class failed', 'xlmain11.chm', 0, -2146827284), None)

在Stackoverflow搜索到了这个问题的解决方法 1,根据Windows位数在目标目录创建一个Desktop文件夹:

  • 64位系统: C:\Windows\SysWOW64\config\systemprofile\
  • 32位系统: C:\Windows\System32\config\systemprofile\

虽然暂时解决了问题,却也不知是何缘由。经历后续问题才明白:Excel需要有Interactive User登陆才能正常运行,上面的步骤正是为其提供了用户“桌面”;然而一旦需要更多用户账户相关的设置时,就会有新的问题出现了。

Programmatic access to Visual Basic Project is not trusted

(-2147352567, 'Exception occurred.', 
(0, 'Microsoft Excel', 'Programmatic access to Visual Basic Project is not trusted\n', 'xlmain11.chm', 0, -2146827284), None)

这个问题很明显,一旦代码需要访问VBA工程对象,例如访问module对象、Python动态执行VBA代码,则需要相应的许可(Excel软件信任区设置中有该选项)。

解决方法可以是利用Python动态修改相应注册表项和值来允许访问VB工程,或者参考 2 手工永久设置。

执行VBA代码超时

这一般是因为VBA代码中存在错误。因为本文的自动化过程是由Python驱动的,一旦VBA代码出错而被挂起,Python就无法得到响应了。

针对本文应用场景的解决方案是在VBA测试代码的开头加上一句On Error Resume Nest,即忽略VBA代码中的错误,以便Python可以正常执行后续流程。并且无需担心此举造成的错误,VBA代码存在错误必将导致后续验证输出的失败,也就表明了这个测试案例必将失败。

无法正确加载VBA中调用的C++动态链接库

VBA代码中直接通过文件名引用DLL,而DLL所在路径已经添加到了PATH环境变量中。由此看来,以系统服务方式启动的Excel并不能正确获取到环境变量。

Declare Function xxx Lib "sample_dll_name.dll" ( arguments_list_xxx ) As xxx

解决方法为通过DCOMConfig设置启动Excel的用户 3 4

  1. Windows+R -> dcomcnfg,打开Component Service
  2. Console Root -> Component Services -> My Computer -> DCOM Config
  3. DCOM Config中找到Microsoft Excel Application,右键选择Properties
    • 选择Identity选项卡,选择the launching user,表示以登陆用户来启动Excel(这里可能会出现新的问题,参见问题5)
    • 选择Security选项卡,为指定的账户自定义Launch and Activation PermissionsAccess Permissions

如果上述DCOM Config列表中并不存在Microsoft Excel Application,则参考下面步骤 4

以64位Windows系统上的32位Excel为例,

  1. Windows+R -> mmc -32打开Microsoft Managemant Console
  2. File -> Add Remove Snap-in -> Component Services -> Add -> OK添加Component Services
  3. DCOMConfig步骤2,3进行设置

The configured identity is incorrect

(-2147467238, 'The server process could not be started because the configured identity is incorrect. 
Check the username and password.', None, None)

到目前为止一切正常,可一旦服务器进入待机状态,就出现了上述错误。原因也很明确,因为之前问题时设置了以当前账户来运行Excel,于是当前用户退出时系统尝试再次登陆,但我们并没有设置任何登陆口令。

解决方法为DCOMConfig设置IdentityThe launching user或者This User,然后输入用户名和密码(注意域内用户需要带上域名称,例如domain\user5

Module has no attribute 'CLSIDToClassMap'

module 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x7' has no attribute 'CLSIDToClassMap'

这是win32comEnsureDispatch()方式启动Excel会产生临时文件夹,出现此问题后只要删除相应文件夹即可,即本例中的00020813-0000-0000-C000-000000000046x0x1x7

import win32com.client    
app = win32com.client.gencache.EnsureDispatch('Excel.Application')

那么如何找到该目录呢?如下代码将打印目标位置 6

import win32com
print(win32com.__gen_path__)
  • 对于本地账户执行的代码:C:\Users\<my username>\AppData\Local\Temp\gen_py
  • 对于系统服务执行的代码:C:\Windows\Temp\gen_py

注意

如果GitLab-runner是系统服务以本地账户形式运行的,则同样对应本地账户目录而非系统目录。

This COM object can not automate the makepy process - please run makepy manually for this object

与上一个问题删除缓存的做法相反,这个错误表明无法自动产生gen_py文件夹,而这正是win32comEnsureDispatch()方式启动Excel所必须的。所以按照提示,手动运行makepy.py即可。

  1. Lib\site-packages\win32com\client目录下执行python makepy.py -d
  2. 在弹出的select library对话框中选择Excel相关的项目即可,例如Microsoft Excel 16.0 Object Library (1.9)
  3. 用户Temp文件夹下即可产生gen_py文件夹

Cannot use object linking and embedding

在正常工作了几天后,突然出现了此问题,具体原因尚不明确。实际上,这是本地账户打开Excel时的错误提示,在GitLab-Runner上执行Excel自动化脚本时表现为失去响应直至超时,即卡在打开Excel工作簿上。

解决方法:

  • 通过DCOMConfig设置系统登陆IdentityThe launching user 7

  • 同时为GitLab-Runner设置登陆账户:将其从默认的Local System切换到This account,然后设置domain\user及其登陆密码。

    1. Windows+R -> services.msc -> gitlab-runner -> properties
    2. Log On -> This account -> 填写PasswordConfirm Password

另外,MSDN上也有人给出了保持DCOMConfigThis account不变而修改本地Excel文件Security属性的解决方法 8,本文尚未是测试。