3

I'm trying to create a COM Object from a dll in a new thread in Python - so I can run a message pump in that thread:

from comtypes.client import CreateObject
import threading

class MessageThread(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.daemon = True

    def run(self):
        print "Thread starting"
        connection = CreateObject("IDMessaging.IDMMFileConnection")
        print "connection created"

a = CreateObject("IDMessaging.IDMMFileConnection")
print "aConnection created"
t = MessageThread()
t.start()

this is the error trace I get:

aConnection created
Thread starting
>>> Exception in thread Thread-1:
Traceback (most recent call last):
  File "c:\python26\lib\threading.py", line 532, in __bootstrap_inner
    self.run()
  File "fred.py", line 99, in run
    self.connection = CreateObject("IDMessaging.IDMMFileConnection")
  File "c:\python26\lib\site-packages\comtypes\client\__init__.py", line 235, in CreateObject
    obj = comtypes.CoCreateInstance(clsid, clsctx=clsctx, interface=interface)
  File "c:\python26\lib\site-packages\comtypes\__init__.py", line 1145, in CoCreateInstance
    _ole32.CoCreateInstance(byref(clsid), punkouter, clsctx, byref(iid), byref(p))
  File "_ctypes/callproc.c", line 925, in GetResult
WindowsError: [Error -2147221008] CoInitialize has not been called

Any ideas?

DangerMouse
  • 89
  • 1
  • 2

4 Answers4

7

You need to have called CoInitialize() (or CoInitializeEx()) on a thread before you can create COM objects on that thread.

from win32com.client.pythoncom import CoInitialize
CoInitialize()
TheNeuralBit
  • 345
  • 1
  • 9
sharptooth
  • 167,383
  • 100
  • 513
  • 979
2

As far as I remember (long time ago I'e programmed a lot with COM Components) you have to call CoInitialize on each thread if your COM Object uses STA.

http://msdn.microsoft.com/en-us/library/ms678543(VS.85).aspx

But I've no idea how to call that function in python.

Here is the MSDN Doc

http://msdn.microsoft.com/en-us/library/ms678543(VS.85).aspx

Arthur
  • 7,939
  • 3
  • 29
  • 46
  • You need CoInitializeEx() regardless of what the object uses. – sharptooth Jul 14 '10 at 13:30
  • many thx to the both of you... I've just done that and now I ole32.dll doesn't appear to return from CoCreateInstance. I'm trying to create the object before I start the message pump - is that ok? – DangerMouse Jul 14 '10 at 14:17
  • Got it... d'oh... my COM DLL is implemented in VB6 and I had it set to STA rather than apartment threaded... all working now... have COM objects on a seperate thread sending messages to Excel ;) – DangerMouse Jul 14 '10 at 15:09
1

Just to update with current experience using PyCharm and Python 2.7: You need to import:

from pythoncom import CoInitializeEx
from pythoncom import CoUninitialize

then for running the thread:

def run(self):
    res = CoInitializeEx(0)
    #<your code>
    CoUninitialize()

PyCharm get confused with STA apartment, you need to enable true multithreading.

It is important that each CoInitialize() is terminated with a CoUninitialize(), so be sure your code follows this rule in case of errors, too.

Juergen
  • 69
  • 5
0

As another answer has said you need to run

CoInitialize()

However it is possible that the COMObject cannot just be passed to the threads directly. You will have to use CoMarshalInterThreadInterfaceInStream() and CoGetInterfaceAndReleaseStream() to pass instance between threads

https://stackoverflow.com/a/27966218/18052428