Python pywin32如何设置COM对象可迭代索引属性的值
问题背景
目前使用pywin32对搭载Automation Server技术接口(原OLE Automation Server)的软件开展自动化任务开发。该软件官方提供的手册包含VBA、C++、Matlab语言的代码示例,但未提供Python相关示例。已自行搭建Python库实现了软件的大部分内置功能,但仍存在部分Python环境下无法实现的操作:无法修改隶属于可迭代COM对象的属性值。
已可正常实现的操作
Visibility属性文档
可通过如下代码修改软件的Visibility属性,控制软件是否显示GUI运行:
import win32com.client app = win32com.client.Dispatch('NAME_OF_APP') app.Visibility = True
目前无法实现的操作
获取与设置当前设备的文档
当尝试为需要指定索引的属性(如CurrentDevice)赋值时,编写如下代码:
import win32com.client app = win32com.client.Dispatch('NAME_OF_APP') app.CurrentDevice(0) = 'NAME OF DEVICE'
运行后会触发如下报错:
SyntaxError: cannot assign to function call here. Maybe you meant '==' instead of '='?
已知该报错的语法含义,但始终未找到为这类以可迭代对象形式存在、需要指定索引的软件属性赋值的方法。据了解C中可通过指针实现这类值的修改,但无C开发基础,希望尽可能通过纯Python实现该功能,避免并行编写C++代码。
已尝试的无效解决方案
- 将索引使用的圆括号
()替换为方括号[]、花括号{},均未生效 - 使用PyCharm的Evaluate功能探查
app.CurrentDevice对象的内部结构,希望找到可直接赋值的子属性,但未发现对象内存在相关可用属性:
CurrentDevice对象的Evaluate结果 - 尝试先将索引对应的对象赋值给变量后再修改变量值,代码如下:
import win32com.client app = win32com.client.Dispatch('NAME_OF_APP') curr_device = app.CurrentDevice(0) curr_device = 'NAME OF DEVICE'
该操作仅会重写curr_device变量本身为字符串'NAME OF DEVICE',完全断开了与原COM对象的关联,无法实现修改COM对象属性的效果。
经检索,该问题存在同类未解决的公开技术提问。
解决方案
纯Python环境下可通过pywin32提供的底层IDispatch调用接口实现,无需编写C++代码,具体操作如下:
- 导入依赖模块
import win32com.client import pythoncom
- 通用兼容方案(适配所有遵循IDispatch规范的Automation Server对象)
先获取目标属性的调度ID(DISPID),再通过Invoke方法执行属性写入操作,注意参数顺序:索引参数放在参数列表最后,写入值放在索引参数之前,同时指定调用类型为属性赋值:
app = win32com.client.Dispatch('NAME_OF_APP') # 获取CurrentDevice属性的DISPID attr_dispid = app._oleobj_.GetIDsOfNames('CurrentDevice') # 给索引为0的CurrentDevice属性赋值 app._oleobj_.Invoke( attr_dispid, 0, pythoncom.DISPATCH_PROPERTYPUT, False, 'NAME OF DEVICE', # 待写入的属性值 0 # 属性索引,多索引属性按顺序在后面追加索引参数即可 )
- 简化写法(适配标准实现的COM对象)
可以切换到早期绑定模式,让pywin32自动生成COM对象的类型包装,部分符合COM规范的索引属性支持直接用方括号赋值:
# 触发早期绑定包装生成 app = win32com.client.gencache.EnsureDispatch('NAME_OF_APP') # 直接通过方括号索引赋值 app.CurrentDevice[0] = 'NAME OF DEVICE'
如果早期绑定模式下方括号赋值抛出不支持的错误,直接使用上面的Invoke底层调用方法即可,该方法不依赖COM端的额外实现,兼容性覆盖所有Automation Server对象。
内容的提问来源于stack exchange,提问作者Pierre Trott

