0

I use this solution to get collection of my parsers/wrappers on COM interface objects concurrently. Like this:

    def _get_interface_containers_concurrent(
        self,
        com_interface_containers: List["win32com"],
        interface_container_type: Type[InterfaceContainer]
        ) -> List[InterfaceContainer]:
    """Get interface containers concurrently.

    Uses this solution: https://stackoverflow.com/a/27966218/4465708

    .. note:: see the class docstring for the current caveats of using this.

    :param com_interface_containers: a list of COM objects that correspond to an interface container
    :param interface_container_type: a type to wrap with the parser Element object (that wraps the COM one)
    :return: a list of wrapped interface containers
    """
    def add_ic(id_, repoid, lst: list, ic_type: Type[InterfaceContainer]) -> None:
        pythoncom.CoInitialize()
        ic_obj = win32com.client.Dispatch(
            pythoncom.CoGetInterfaceAndReleaseStream(id_, pythoncom.IID_IDispatch))
        repo_obj = win32com.client.Dispatch(
            pythoncom.CoGetInterfaceAndReleaseStream(repoid, pythoncom.IID_IDispatch))

        ic_el = Element(ic_obj)
        print(f"{ic_el.name!r} has been parsed.")
        ic = ic_type(ic_el, repo_obj)
        lst.append(ic)
        print(f"{ic.name!r} {ic_type.__name__} created.")

    result, workers = [], []
    for com_ic in com_interface_containers:
        ic_id = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch, com_ic)
        repo_id = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch,
                                                                  self._repo)
        t = Thread(target=add_ic, args=(ic_id, repo_id, result, interface_container_type))
        workers.append(t)
        t.start()

    for w in workers:
        w.join()

    print("Parsing completed.")
    return result

This works. At least as long as I only access data parsed and stored on the wrapper objects. As soon as I try to access the wrapped COM object after the threads are joined with the main I get:

com_error: (-2147220995, 'Object is not connected to server', None, None)

Is there some way to get around this? I assume I should probably do something with those COM objects before join. Or maybe, there is some way I can reconnect those objects with the COM server afterwards. Any ideas?

I found a corresponding question on the python-win32 mailing list dating back to 2006. But it seems, even though plenty of time had passed since, there is no answer anywhere for it.

z33k
  • 3,280
  • 6
  • 24
  • 38
  • 1
    I am not an expert on this, but FWIW have had difficulty in Python when I've tried to call methods on interface pointers passed between threads. It seems the default model for CoInitialize() is COINIT_APARTMENTTHREADED (http://timgolden.me.uk/pywin32-docs/pythoncom__CoInitialize_meth.html) : perhaps explore other models, eg COINIT_MULTITHREADED? I found this explanation on SO: https://stackoverflow.com/questions/19882174/coinitializenil-and-coinitializeex0-coinit-multithreaded-difference – DS_London Nov 08 '21 at 14:59
  • @DS_London: I changed `pythoncom.CoInitialize()` call to `pythoncom.CoInitializeEx(pythoncom.COINIT_MULTITHREADED)`. The result is the same. Thx for the SO link though, at least this seems like an avenue to explore if I only find the time. – z33k Nov 09 '21 at 16:06

0 Answers0