导入 pywinauto(或 comtypes)会破坏现有的 COM 对象

Importing pywinauto (or comtypes) clobbers existing COM object

使用 win32com.client.GetActiveObject 创建/获取 COM 对象,然后 import pywintypes 在每次调用原始 COM 对象时产生 AttributeError

重现代码

import win32com.client
catia_com = win32com.client.GetActiveObject('CATIA.Application')

# then later when needed, do some pywinauto stuff
import pywinauto.application

# back to working directly on catia com object
print(catia.caption)  # raises Attribute error from within win32com.client

为什么会发生这种情况,如何解决?

我找到了一个解决方案,我想分享一下,但我也想听听关于我的理解的反馈,以及应该解决这个问题的适当依赖是什么,以防止其他人拥有同样的问题。

解决方案

在调用win32com.client之前添加import comtypes

例子

import comtypes
import win32com.client
catia_com = win32com.client.GetActiveObject('CATIA.Application')

# then later when needed, do some pywinauto stuff
import pywinauto.application

# back to working directly on catia com object
print(catia.caption)  # it works!

原因和解释(尽我所能确定)

TLDR

import comtypes 使用标志 COINIT_MULTITHREADED 调用 CoInitializeEx,这恰好覆盖了 win32com.client.GetActiveObject 设置的模式。

完整解释

我得出这个结论是因为在 pywinauto.__init__ 中注释掉 pythoncom.CoUninitialize()(我担心它会杀死从 win32com.client.GetActiveObject 返回的 COM 对象)并重新运行以下代码错误来自 comtypes.__init__:

OSError: [WinError -2147417850] Cannot change thread mode after it is set

我知道 comtypes.__init__ handels 选择了 CoInitializeEx 的默认标志并且无法推断出 win32com 库是怎样的,但我认为它也可能正在检查现有标志,所以我添加了 import comtypes.

我还不清楚的地方

  1. 如何确定 win32com 的并发模型标志是什么?
  2. 调用win32com.client.GetActiveObject时如何指定并发模型标志?
  3. 为什么解决方案有效...在调用 win32com.client.GetActiveObject 之前调用 pythoncom.CoInitializeEx(0x0) 不起作用!

如果我能得到上面的答案,我可以建议 win32com 设置 sys.coinit_flags(这是 comtypes.__init__ 正在检查的地方)。

资源