Python、COM与多线程问题

6 投票
1 回答
2296 浏览
提问于 2025-04-17 09:27

我正在尝试从一个单独的线程查看IE的DOM(文档对象模型),但是在访问某些属性时遇到了“没有这样的接口支持”的错误。我把问题简化成了下面这个脚本:

import threading, time

import pythoncom
from win32com.client import Dispatch, gencache
gencache.EnsureModule('{3050F1C5-98B5-11CF-BB82-00AA00BDCE0B}', 0, 4, 0) # MSHTML

def main():
    pythoncom.CoInitializeEx(0)
    ie = Dispatch('InternetExplorer.Application')
    ie.Visible = True
    ie.Navigate('http://www.Rhodia-ecommerce.com/')
    while ie.Busy:
        time.sleep(1)

    def printframes():
        pythoncom.CoInitializeEx(0)
        document = ie.Document
        frames = document.getElementsByTagName(u'frame')
        for frame in frames:
            obj = frame.contentWindow

    thr = threading.Thread(target=printframes)
    thr.start()
    thr.join()

if __name__ == '__main__':
    thr = threading.Thread(target=main)
    thr.start()
    thr.join()

在访问frame.contentWindow之前一切都很好。然后就出问题了:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\python22\lib\threading.py", line 414, in __bootstrap
    self.run()
  File "C:\python22\lib\threading.py", line 402, in run
    apply(self.__target, self.__args, self.__kwargs)
  File "testie.py", line 42, in printframes
    obj = frame.contentWindow
  File "C:\python22\lib\site-packages\win32com\client\__init__.py", line 455, in __getattr__
    return self._ApplyTypes_(*args)
  File "C:\python22\lib\site-packages\win32com\client\__init__.py", line 446, in _ApplyTypes_
    return self._get_good_object_(
com_error: (-2147467262, 'No such interface supported', None, None)

有没有什么提示?

1 个回答

1

正确的做法是手动处理这些东西。这不是一个变通办法,而是你应该这样做。你其实不需要使用公寓线程。

你初始化的时候选择了多线程公寓,这告诉COM(组件对象模型)它可以在任何线程上调用你的接口。但这并不意味着你可以在任何线程上调用其他接口,也不能免除你对COM提供的接口进行处理的责任。这样做可能只会“偶然”成功,比如如果你调用的对象恰好是一个进程内的MTA对象,那就没关系了。

CoMarshalInterThreadInterfaceInStreamCoGetInterfaceAndReleaseStream是处理这个问题的工具。

这样做的原因是,对象可以提供自己的代理,这些代理可能是自由线程的,也可能不是。(或者确实提供自定义的处理方式)。你需要进行处理,以告诉它们正在不同的线程之间移动。如果代理是自由线程的,你可能会得到同一个指针。

撰写回答