python, COM and multithreading issue

拈花ヽ惹草 提交于 2021-02-19 01:01:07

问题


I'm trying to take a look at IE's DOM from a separate thread that dispatched IE, and for some properties I'm getting a "no such interface supported" error. I managed to reduce the problem to this script:

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()

Everything is fine until the frame.contentWindow. Then bam:

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)

Any hint ?


回答1:


The correct answer is to marshal stuff by hand. That's not a workaround it is what you are supposed to do here. You shouldn't have to use apartment threading though.

You initialised as multithreaded apartment - that tells COM that it can call your interfaces on any thread. It does not allow you to call other interfaces on any thread, or excuse you from marshalling interfaces provided by COM. That will only work "by accident" - E.g. if the object you are calling happens to be an in-process MTA object, it won't matter.

CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream does the business.

The reason for this is that objects can provide their own proxies, which may or may not be free-threaded. (Or indeed provide custom marshalling). You have to marshal them to tell them they are moving between threads. If the proxy is free threaded, you may get the same pointer back.



来源:https://stackoverflow.com/questions/8712806/python-com-and-multithreading-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!