[python-win32] Bug in pythoncom.CoInitialize(Ex)

Mark Hammond mhammond at skippinet.com.au
Wed Nov 9 02:36:57 CET 2005


There is a subtle bug in CoInitialize and CoInitializeEx.  I'd like some
feedback on how to best fix it.

The problem is that error results from these functions are not reported
correctly.  This is best demonstrated by example:

--- coinit.py ---
import thread, time
import pythoncom

def wtf():
    pythoncom.CoInitializeEx(0)
    pythoncom.CoInitialize()
    # Uncomment the next line to see the error ignored.
    #getattr(pythoncom, "foo", None)
    if type(0) in [int, str]:
        pass

thread.start_new(wtf, ())
time.sleep(0.5)

--- end ---

Running this as it stands yields:

Unhandled exception in thread started by <function wtf at 0x008EF458>
Traceback (most recent call last):
  File "coinit.py", line 9, in wtf
    if type(0) in [int, str]:
pywintypes.com_error: (-2147417850, 'Cannot change thread mode after it is
set.', None, None)

Note that the traceback does *not* point at the CoInit calls - it points at
the 'if' statement.  This also means an exception handler around the CoInit
call fails to catch the error.

If you uncomment the line indicated, the error is completely ignored - the
"getattr" for a non-existing attribute internally masks the "pending" error
set by pythoncom.CoInitialize().

I can see the underlying problem that causes this.  My concern is how to fix
with without breaking code, as there may be code out there today that is
managing to mask this error.  Interestingly though, a thread that calls
CoInit then immediately calls win32com.client.Dispatch *will* see the
error - but as in my example, the traceback will point at the wrong place.
I suspect that many people calling CoInit from a thread *will* immediately
call win32com.client.Dispatch, so I would be quite surprised if it would
break things.

What I propose is that I change CoInitialize() to ignore this specific
RPC_E_CHANGED_MODE error.  My reasoning is that people calling
CoInitialize() don't care about the threading model - all they want is to be
able to use a COM object from their thread.  However, I think
CoInitializeEx() should always raise an exception on error return, including
for that specific error.  My reasoning is that people explicitly calling
CoInitializeEx(thread_model) *do* care about the threading model, and may
take great interest in the fact the thread has already been initialized
differently.  If it is prepared to work in a different threading model, it
just needs to catch the exception.

Does anyone have any comments?

Thanks,

Mark



More information about the Python-win32 mailing list