[Python-checkins] r62366 - in ctypes/trunk/comtypes: ChangeLog comtypes/__init__.py comtypes/_comobject.py comtypes/client/_events.py comtypes/server/automation.py comtypes/server/connectionpoints.py comtypes/server/register.py comtypes/test/TestComServer.py comtypes/test/runtests.py comtypes/test/test_collections.py comtypes/test/test_createwrappers.py
thomas.heller
python-checkins at python.org
Thu Apr 17 19:56:29 CEST 2008
Author: thomas.heller
Date: Thu Apr 17 19:56:27 2008
New Revision: 62366
Log:
Merge in a lot of changes from the private upstream repository (rev
26394); mainly much better support for implementing comtypes servers.
Modified:
ctypes/trunk/comtypes/ChangeLog
ctypes/trunk/comtypes/comtypes/__init__.py
ctypes/trunk/comtypes/comtypes/_comobject.py
ctypes/trunk/comtypes/comtypes/client/_events.py
ctypes/trunk/comtypes/comtypes/server/automation.py
ctypes/trunk/comtypes/comtypes/server/connectionpoints.py
ctypes/trunk/comtypes/comtypes/server/register.py
ctypes/trunk/comtypes/comtypes/test/TestComServer.py
ctypes/trunk/comtypes/comtypes/test/runtests.py
ctypes/trunk/comtypes/comtypes/test/test_collections.py
ctypes/trunk/comtypes/comtypes/test/test_createwrappers.py
Modified: ctypes/trunk/comtypes/ChangeLog
==============================================================================
--- ctypes/trunk/comtypes/ChangeLog (original)
+++ ctypes/trunk/comtypes/ChangeLog Thu Apr 17 19:56:27 2008
@@ -1,3 +1,9 @@
+2008-04-17 Thomas Heller <theller at python.net>
+
+ * Merge in a lot of changes from the private upstream repository
+ 26394; mainly much better support for implementing comtypes
+ servers.
+
2008-04-09 Thomas Heller <theller at python.net>
* Bump version number to 0.4.3a
Modified: ctypes/trunk/comtypes/comtypes/__init__.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/__init__.py (original)
+++ ctypes/trunk/comtypes/comtypes/__init__.py Thu Apr 17 19:56:27 2008
@@ -28,6 +28,13 @@
monkeypatch_COMError()
del monkeypatch_COMError
+class ReturnHRESULT(Exception):
+ """ReturnHRESULT(hresult, text)
+
+ Return a hresult code from a COM method implementation
+ without logging an error.
+ """
+
import logging
logger = logging.getLogger(__name__)
Modified: ctypes/trunk/comtypes/comtypes/_comobject.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/_comobject.py (original)
+++ ctypes/trunk/comtypes/comtypes/_comobject.py Thu Apr 17 19:56:27 2008
@@ -2,48 +2,133 @@
from comtypes.hresult import *
import os
+import new
import logging
logger = logging.getLogger(__name__)
_debug = logger.debug
_warning = logger.warning
+_error = logger.error
################################################################
# COM object implementation
from _ctypes import CopyComPointer
-def prepare_comobject(inst):
- # When a CoClass instance is created, COM pointers to all
- # interfaces are created. Also, the CoClass must be kept alive as
- # until the COM reference count drops to zero, even if no Python
- # code keeps a reference to the object.
- #
- # The _com_pointers_ instance variable maps string interface iids
- # to C compatible COM pointers.
- inst._com_pointers_ = {}
- # COM refcount starts at zero.
- inst._refcnt = c_long(0)
- for itf in inst._com_interfaces_[::-1]:
- make_interface_pointer(inst, itf)
+from comtypes import COMError, ReturnHRESULT
+from comtypes.errorinfo import ISupportErrorInfo, ReportException, ReportError
+from comtypes.typeinfo import IProvideClassInfo, IProvideClassInfo2
+from comtypes import IPersist
+
+class E_NotImplemented(Exception):
+ """COM method is not implemented"""
+
+def HRESULT_FROM_WIN32(errcode):
+ "Convert a Windows error code into a HRESULT value."
+ if errcode is None:
+ return 0x80000000
+ if errcode & 0x80000000:
+ return errcode
+ return (errcode & 0xFFFF) | 0x80070000
+
+def winerror(exc):
+ """Return the windows error code from a WindowsError or COMError
+ instance."""
+ try:
+ code = exc[0]
+ if isinstance(code, (int, long)):
+ return code
+ except IndexError:
+ pass
+ # Sometimes, a WindowsError instance has no error code. An access
+ # violation raised by ctypes has only text, for example. In this
+ # cases we return a generic error code.
+ return E_FAIL
-from comtypes.errorinfo import ReportException
+def _do_implement(interface_name, method_name):
+ def _not_implemented(*args):
+ """Return E_NOTIMPL because the method is not implemented."""
+ _debug("unimplemented method %s_%s called", interface_name, method_name)
+ return E_NOTIMPL
+ return _not_implemented
-def catch_errors(obj, mth, interface):
- iid = interface._iid_
+def catch_errors(obj, mth, interface, mthname):
clsid = getattr(obj, "_reg_clsid_", None)
def func(*args, **kw):
try:
return mth(*args, **kw)
- except Exception:
- _warning("%s", interface, exc_info=True)
- return ReportException(E_FAIL, iid, clsid=clsid)
+ except ReturnHRESULT, (hresult, text):
+ return ReportError(text, iid=interface._iid_, clsid=clsid, hresult=hresult)
+ except (COMError, WindowsError), details:
+ _error("Exception in %s.%s implementation:", interface.__name__, mthname, exc_info=True)
+ return HRESULT_FROM_WIN32(winerror(details))
+ except E_NotImplemented:
+ _warning("Unimplemented method %s.%s called", interface.__name__, mthname)
+ return E_NOTIMPL
+ except:
+ _error("Exception in %s.%s implementation:", interface.__name__, mthname, exc_info=True)
+ return ReportException(E_FAIL, interface._iid_, clsid=clsid)
return func
-def _do_implement(interface_name, method_name):
- def _not_implemented(*args):
- """Return E_NOTIMPL because the method is not implemented."""
- _debug("unimplemented method %s_%s called", interface_name, method_name)
- return E_NOTIMPL
- return _not_implemented
+################################################################
+
+def hack(inst, mth, paramflags, interface, mthname):
+ if paramflags is None:
+ return catch_errors(inst, mth, interface, mthname)
+ code = mth.func_code
+ if code.co_varnames[1:2] == ("this",):
+ return catch_errors(inst, mth, interface, mthname)
+ dirflags = [f[0] for f in paramflags]
+ # An argument is [IN] if it is not [OUT] !
+ # This handles the case where no direction is defined in the IDL file.
+ # number of input arguments:
+ args_in = len([f for f in dirflags if (f & 2) == 0])
+ # number of output arguments:
+ args_out = len([f for f in dirflags if f & 2])
+ if args_in != code.co_argcount - 1:
+ return catch_errors(inst, mth, interface, mthname)
+ # This code assumes that input args are always first, and output
+ # args are always last. Have to check with the IDL docs if this
+ # is always correct.
+
+ clsid = getattr(inst, "_reg_clsid_", None)
+ def wrapper(this, *args):
+ outargs = args[len(args)-args_out:]
+ for a in outargs:
+ if not a:
+ return E_POINTER
+ try:
+ result = mth(*args[:args_in])
+ if args_out == 1:
+ outargs[0][0] = result
+ elif args_out != 0:
+ if len(result) != args_out:
+ raise ValueError("Method should have returned a %s-tuple" % args_out)
+ for i, value in enumerate(result):
+ outargs[i][0] = value
+ except ReturnHRESULT, (hresult, text):
+ return ReportError(text, iid=interface._iid_, clsid=clsid, hresult=hresult)
+ except COMError, (hr, text, details):
+ _error("Exception in %s.%s implementation:", interface.__name__, mthname, exc_info=True)
+ try:
+ descr, source, helpfile, helpcontext, progid = details
+ except (ValueError, TypeError):
+ msg = str(details)
+ else:
+ msg = "%s: %s" % (source, descr)
+ hr = HRESULT_FROM_WIN32(hr)
+ return ReportError(msg, iid=interface._iid_, clsid=clsid, hresult=hr)
+ except WindowsError, details:
+ _error("Exception in %s.%s implementation:", interface.__name__, mthname, exc_info=True)
+ hr = HRESULT_FROM_WIN32(winerror(details))
+ return ReportException(hr, interface._iid_, clsid=clsid)
+ except E_NotImplemented:
+ _warning("Unimplemented method %s.%s called", interface.__name__, mthname)
+ return E_NOTIMPL
+ except:
+ _error("Exception in %s.%s implementation:", interface.__name__, mthname, exc_info=True)
+ return ReportException(E_FAIL, interface._iid_, clsid=clsid)
+ return S_OK
+
+ return wrapper
class _MethodFinder(object):
def __init__(self, inst):
@@ -51,44 +136,61 @@
# map lower case names to names with correct spelling.
self.names = dict([(n.lower(), n) for n in dir(inst)])
- def get_impl(self, interface, mthname):
+ def get_impl(self, instance, interface, mthname, paramflags, idlflags):
+ mth = self.find_impl(interface, mthname, paramflags, idlflags)
+ if mth is None:
+ return _do_implement(interface.__name__, mthname)
+ return hack(self.inst, mth, paramflags, interface, mthname)
+
+ def find_impl(self, interface, mthname, paramflags, idlflags):
fq_name = "%s_%s" % (interface.__name__, mthname)
if interface._case_insensitive_:
mthname = self.names.get(mthname.lower(), mthname)
fq_name = self.names.get(fq_name.lower(), fq_name)
+
try:
- # try the simple name, like 'QueryInterface'
- return getattr(self.inst, mthname)
+ # qualified name, like 'IUnknown_QueryInterface'
+ return getattr(self.inst, fq_name)
except AttributeError:
pass
try:
- # qualified name, like 'IUnknown_QueryInterface'
- return getattr(self.inst, fq_name)
+ # simple name, like 'QueryInterface'
+ return getattr(self.inst, mthname)
except AttributeError:
- # use method that returns E_NOTIMPL when called.
- _debug("%r: %s.%s not implemented", self.inst, interface.__name__, mthname)
- return _do_implement(interface.__name__, mthname)
+ pass
+ propname = mthname[5:]
+ if interface._case_insensitive_:
+ propname = self.names.get(propname.lower(), propname)
+ # propput and propget is done with 'normal' attribute access,
+ # but only for COM properties that do not take additional
+ # arguments:
+
+ if "propget" in idlflags and len(paramflags) == 1:
+ return self.getter(propname)
+ if "propput" in idlflags and len(paramflags) == 1:
+ return self.setter(propname)
+ _debug("%r: %s.%s not implemented", self.inst, interface.__name__, mthname)
+ return None
+
+ def setter(self, propname):
+ #
+ def set(self, value):
+ try:
+ # XXX this may not be correct is the object implements
+ # _get_PropName but not _set_PropName
+ setattr(self, propname, value)
+ except AttributeError:
+ raise E_NotImplemented()
+ return new.instancemethod(set, self.inst, type(self.inst))
-def make_interface_pointer(inst, itf,
- _debug=_debug):
- methods = [] # method implementations
- fields = [] # (name, prototype) for virtual function table
- iids = [] # interface identifiers.
- # iterate over interface inheritance in reverse order to build the
- # virtual function table, and leave out the 'object' base class.
- finder = _MethodFinder(inst)
- for interface in itf.__mro__[-2::-1]:
- iids.append(interface._iid_)
- for m in interface._methods_:
- restype, mthname, argtypes, paramflags, idlflags, helptext = m
- proto = WINFUNCTYPE(restype, c_void_p, *argtypes)
- fields.append((mthname, proto))
- mth = finder.get_impl(interface, mthname)
- methods.append(proto(mth))
- Vtbl = _create_vtbl_type(tuple(fields), itf)
- vtbl = Vtbl(*methods)
- for iid in iids:
- inst._com_pointers_[iid] = pointer(pointer(vtbl))
+ def getter(self, propname):
+ #
+ def get(self):
+ try:
+ return getattr(self, propname)
+ except AttributeError:
+ raise E_NotImplemented()
+ return new.instancemethod(get, self.inst, type(self.inst))
def _create_vtbl_type(fields, itf):
try:
@@ -109,39 +211,80 @@
_InterlockedIncrement = windll.coredll.InterlockedIncrement
_InterlockedDecrement = windll.coredll.InterlockedDecrement
else:
- try:
- _InterlockedIncrement = windll.kernel32.InterlockedIncrement
- _InterlockedDecrement = windll.kernel32.InterlockedDecrement
- except AttributeError:
- import thread
- _lock = thread.allocate_lock()
-
- def _InterlockedIncrement(obj):
- _lock.acquire()
- result = obj._obj.value = obj._obj.value + 1
- _lock.release()
- return result
-
- def _InterlockedDecrement(obj):
- _lock.acquire()
- result = obj._obj.value = obj._obj.value - 1
- _lock.release()
- return result
+ _InterlockedIncrement = windll.kernel32.InterlockedIncrement
+ _InterlockedDecrement = windll.kernel32.InterlockedDecrement
class COMObject(object):
_instances_ = {}
_factory = None
def __new__(cls, *args, **kw):
- self = super(COMObject, cls).__new__(cls)
+ self = super(COMObject, cls).__new__(cls, *args, **kw)
if isinstance(self, c_void_p):
# We build the VTables only for direct instances of
# CoClass, not for POINTERs to CoClass.
return self
if hasattr(self, "_com_interfaces_"):
- prepare_comobject(self)
+ self.__prepare_comobject()
return self
+ def __prepare_comobject(self):
+ # When a CoClass instance is created, COM pointers to all
+ # interfaces are created. Also, the CoClass must be kept alive as
+ # until the COM reference count drops to zero, even if no Python
+ # code keeps a reference to the object.
+ #
+ # The _com_pointers_ instance variable maps string interface iids
+ # to C compatible COM pointers.
+ self._com_pointers_ = {}
+ # COM refcount starts at zero.
+ self._refcnt = c_long(0)
+
+ # Some interfaces have a default implementation in COMObject:
+ # - ISupportErrorInfo
+ # - IPersist (if the subclass has a _reg_clsid_ attribute)
+ # - IProvideClassInfo (if the subclass has a _reg_clsid_ attribute)
+ # - IProvideClassInfo2 (if the subclass has a _outgoing_interfaces_ attribute)
+ #
+ # Add these if they are not listed in _com_interfaces_.
+ interfaces = tuple(self._com_interfaces_)
+ if ISupportErrorInfo not in interfaces:
+ interfaces += (ISupportErrorInfo,)
+ if hasattr(self, "_reg_typelib_"):
+ from comtypes.typeinfo import LoadRegTypeLib
+ self._COMObject__typelib = LoadRegTypeLib(*self._reg_typelib_)
+ if hasattr(self, "_reg_clsid_"):
+ if IProvideClassInfo not in interfaces:
+ interfaces += (IProvideClassInfo,)
+ if hasattr(self, "_outgoing_interfaces_") and \
+ IProvideClassInfo2 not in interfaces:
+ interfaces += (IProvideClassInfo2,)
+ if hasattr(self, "_reg_clsid_"):
+ if IPersist not in interfaces:
+ interfaces += (IPersist,)
+ for itf in interfaces[::-1]:
+ self.__make_interface_pointer(itf)
+
+ def __make_interface_pointer(self, itf):
+ methods = [] # method implementations
+ fields = [] # (name, prototype) for virtual function table
+ iids = [] # interface identifiers.
+ # iterate over interface inheritance in reverse order to build the
+ # virtual function table, and leave out the 'object' base class.
+ finder = _MethodFinder(self)
+ for interface in itf.__mro__[-2::-1]:
+ iids.append(interface._iid_)
+ for m in interface._methods_:
+ restype, mthname, argtypes, paramflags, idlflags, helptext = m
+ proto = WINFUNCTYPE(restype, c_void_p, *argtypes)
+ fields.append((mthname, proto))
+ mth = finder.get_impl(self, interface, mthname, paramflags, idlflags)
+ methods.append(proto(mth))
+ Vtbl = _create_vtbl_type(tuple(fields), itf)
+ vtbl = Vtbl(*methods)
+ for iid in iids:
+ self._com_pointers_[iid] = pointer(pointer(vtbl))
+
#########################################################
# IUnknown methods implementations
def IUnknown_AddRef(self, this,
@@ -191,11 +334,105 @@
_debug("%r.QueryInterface(%s) -> E_NOINTERFACE", self, iid)
return E_NOINTERFACE
+ def QueryInterface(self, interface):
+ "Query the object for an interface pointer"
+ # This method is NOT the implementation of
+ # IUnknown::QueryInterface, instead it is supposed to be
+ # called on an COMObject by user code. It allows to get COM
+ # interface pointers from COMObject instances.
+ ptr = self._com_pointers_.get(interface._iid_, None)
+ if ptr is None:
+ raise COMError(E_NOINTERFACE, FormatError(E_NOINTERFACE),
+ (None, None, 0, None, None))
+ # CopyComPointer(src, dst) calls AddRef!
+ result = POINTER(interface)()
+ CopyComPointer(ptr, byref(result))
+ return result
+
################################################################
- # ISupportErrorInfo method implementation
+ # ISupportErrorInfo::InterfaceSupportsErrorInfo implementation
def ISupportErrorInfo_InterfaceSupportsErrorInfo(self, this, riid):
if riid[0] in self._com_pointers_:
return S_OK
return S_FALSE
+ ################################################################
+ # IProvideClassInfo::GetClassInfo implementation
+ def IProvideClassInfo_GetClassInfo(self):
+ try:
+ self.__typelib
+ except AttributeError:
+ raise WindowsError(E_NOTIMPL)
+ return self.__typelib.GetTypeInfoOfGuid(self._reg_clsid_)
+
+ ################################################################
+ # IProvideClassInfo2::GetGUID implementation
+
+ def IProvideClassInfo2_GetGUID(self, dwGuidKind):
+ # GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1
+ if dwGuidKind != 1:
+ raise WindowsError(E_INVALIDARG)
+ return self._outgoing_interfaces_[0]._iid_
+
+ ################################################################
+ # IDispatch methods
+ @property
+ def __typeinfo(self):
+ # XXX Looks like this better be a static property, set by the
+ # code that sets __typelib also...
+ iid = self._com_interfaces_[0]._iid_
+ return self.__typelib.GetTypeInfoOfGuid(iid)
+
+ def IDispatch_GetTypeInfoCount(self):
+ try:
+ self.__typelib
+ except AttributeError:
+ return 0
+ else:
+ return 1
+
+ def IDispatch_GetTypeInfo(self, itinfo, lcid):
+ if itinfo != 0:
+ raise WindowsError(DISP_E_BADINDEX)
+ try:
+ self.__typelib
+ except AttributeError:
+ raise WindowsError(E_NOTIMPL)
+ else:
+ return self.__typeinfo
+
+ def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, rgDispId):
+ # Use windll to let DispGetIDsOfNames return a HRESULT instead
+ # of raising an error:
+ try:
+ self.__typeinfo
+ except AttributeError:
+ return E_NOTIMPL
+ return windll.oleaut32.DispGetIDsOfNames(self.__typeinfo,
+ rgszNames, cNames, rgDispId)
+
+ def IDispatch_Invoke(self, this, dispIdMember, riid, lcid, wFlags,
+ pDispParams, pVarResult, pExcepInfo, puArgErr):
+ try:
+ self.__typeinfo
+ except AttributeError:
+ # Hm, we pretend to implement IDispatch, but have no
+ # typeinfo, and so cannot fulfill the contract. Should we
+ # better return E_NOTIMPL or DISP_E_MEMBERNOTFOUND? Some
+ # clients call IDispatch_Invoke with 'known' DISPID_...'
+ # values, without going through GetIDsOfNames first.
+ return DISP_E_MEMBERNOTFOUND
+ impl = self._com_pointers_[self._com_interfaces_[0]._iid_]
+ # Use windll to let DispInvoke return a HRESULT instead
+ # of raising an error:
+ return windll.oleaut32.DispInvoke(impl,
+ self.__typeinfo,
+ dispIdMember, wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr)
+
+ ################################################################
+ # IPersist interface
+ def IPersist_GetClassID(self):
+ return self._reg_clsid_
+
__all__ = ["COMObject"]
Modified: ctypes/trunk/comtypes/comtypes/client/_events.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/client/_events.py (original)
+++ ctypes/trunk/comtypes/comtypes/client/_events.py Thu Apr 17 19:56:27 2008
@@ -50,9 +50,18 @@
self.cookie = self.cp.Advise(receiver)
self.receiver = receiver
+ def disconnect(self):
+ if self.cookie:
+ self.cp.Unadvise(self.cookie)
+ logger.debug("Unadvised %s", self.cp)
+ self.cp = None
+ self.cookie = None
+ del self.receiver
+
def __del__(self):
try:
- self.cp.Unadvise(self.cookie)
+ if self.cookie is not None:
+ self.cp.Unadvise(self.cookie)
except (comtypes.COMError, WindowsError):
# Are we sure we want to ignore errors here?
pass
Modified: ctypes/trunk/comtypes/comtypes/server/automation.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/server/automation.py (original)
+++ ctypes/trunk/comtypes/comtypes/server/automation.py Thu Apr 17 19:56:27 2008
@@ -4,79 +4,11 @@
from comtypes.hresult import *
from comtypes import COMObject, IUnknown
-from comtypes.typeinfo import LoadRegTypeLib, IProvideClassInfo, IProvideClassInfo2
from comtypes.automation import IEnumVARIANT
logger = logging.getLogger(__name__)
-_oleaut32 = windll.oleaut32
-
-__all__ = ["DualDispImplMixin", "VARIANTEnumerator"]
-
-class DualDispImplMixin(object):
- # a mixin class to implement a dual dispatch interface.
- # Needs a _reg_typelib_ attribute in the subclass.
- #
- # Also implements IProvideClassInfo2. XXX Where should this
- # really go? And: XXX Can we load the typelib in the CoClass
- # baseclass?
- def __init__(self):
- super(DualDispImplMixin, self).__init__()
- tlib = LoadRegTypeLib(*self._reg_typelib_)
-
- # XXX This works only if the default dispatch interface is
- # also the default interface. We should either search for the
- # first dispatch interface, or raise an error if the first is
- # no default disp interface.
- self.__dispatch_iid = self._com_interfaces_[0]._iid_
- self.__tinfo = tlib.GetTypeInfoOfGuid(self.__dispatch_iid)
- if hasattr(self, "_reg_clsid_"):
- self.__coclass_tinfo = tlib.GetTypeInfoOfGuid(self._reg_clsid_)
-
- def IDispatch_GetTypeInfoCount(self, this, pctinfo):
- if not pctinfo:
- return E_POINTER
- pctinfo[0] = 1
- return S_OK
-
- def IDispatch_GetTypeInfo(self, this, itinfo, lcid, pptinfo):
- if not pptinfo:
- return E_POINTER
- if itinfo != 0:
- return DISP_E_BADINDEX
- pptinfo[0] = self.__tinfo
- return S_OK
-
- def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, rgDispId):
- return _oleaut32.DispGetIDsOfNames(self.__tinfo, rgszNames, cNames, rgDispId)
-
- def IDispatch_Invoke(self, this, dispIdMember, riid, lcid, wFlags,
- pDispParams, pVarResult, pExcepInfo, puArgErr):
- impl = self._com_pointers_[self.__dispatch_iid]
- return _oleaut32.DispInvoke(impl, self.__tinfo,
- dispIdMember, wFlags, pDispParams,
- pVarResult, pExcepInfo, puArgErr)
-
- def IProvideClassInfo_GetClassInfo(self, this, ppTI):
- if not ppTI:
- return E_POINTER
- logger.debug("GetClassInfo called for %s", self._reg_clsid_)
- ppTI[0] = self.__coclass_tinfo
- return S_OK
-
- def IProvideClassInfo2_GetGUID(self, this, dwGuidKind, pGUID):
- if not pGUID:
- return E_POINTER
- GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1
- if dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID:
- return E_INVALIDARG
- # XXX MSDN: The outgoing interface in question must be derived from IDispatch.
- iid = self._outgoing_interfaces_[0]._iid_
- memmove(pGUID, byref(iid), sizeof(iid))
- logger.debug("IProvideClassInfo2::GetGUID -> %s", iid)
- return S_OK
-
-################################################################
+__all__ = ["VARIANTEnumerator"]
class VARIANTEnumerator(COMObject):
_com_interfaces_ = [IEnumVARIANT]
Modified: ctypes/trunk/comtypes/comtypes/server/connectionpoints.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/server/connectionpoints.py (original)
+++ ctypes/trunk/comtypes/comtypes/server/connectionpoints.py Thu Apr 17 19:56:27 2008
@@ -58,10 +58,20 @@
# for better performance, we could cache the dispids.
dispid = self._typeinfo.GetIDsOfNames(name)[0]
for p in self._connections.values():
- p.Invoke(dispid, *args, **kw)
+ try:
+ p.Invoke(dispid, *args, **kw)
+ except COMError, details:
+ # XXX for certain errors (server missing) we should unadvise the connection
+ logger.warning("_call_sinks(%s, %s, *%s, **%s)", self, name, args, kw,
+ exc_info=True)
else:
for p in self._connections.values():
- getattr(p, name)(*args, **kw)
+ try:
+ getattr(p, name)(*args, **kw)
+ except COMError, details:
+ # XXX for certain errors (server missing) we should unadvise the connection
+ logger.warning("_call_sinks(%s, %s, *%s, **%s)", self, name, args, kw,
+ exc_info=True)
class ConnectableObjectMixin(object):
"""Mixin which implements IConnectionPointContainer.
Modified: ctypes/trunk/comtypes/comtypes/server/register.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/server/register.py (original)
+++ ctypes/trunk/comtypes/comtypes/server/register.py Thu Apr 17 19:56:27 2008
@@ -286,6 +286,8 @@
if " " in exe:
exe = '"%s"' % exe
if not hasattr(sys, "frozen"):
+ if not __debug__:
+ exe = "%s -O" % exe
script = os.path.abspath(sys.modules[cls.__module__].__file__)
if " " in script:
script = '"%s"' % script
@@ -328,7 +330,7 @@
opts, args = w_getopt.w_getopt(sys.argv[1:],
"regserver unregserver embedding l: f: nodebug")
if not opts:
- sys.stderr.write(usage)
+ sys.stderr.write(usage + "\n")
return 0 # nothing for us to do
levels = []
Modified: ctypes/trunk/comtypes/comtypes/test/TestComServer.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/test/TestComServer.py (original)
+++ ctypes/trunk/comtypes/comtypes/test/TestComServer.py Thu Apr 17 19:56:27 2008
@@ -12,7 +12,6 @@
import comtypes.client
import comtypes.errorinfo
import comtypes.server
-import comtypes.server.automation
import comtypes.server.connectionpoints
import comtypes.typeinfo
@@ -40,7 +39,6 @@
# class.
class TestComServer(
TestComServerLib.TestComServer, # the coclass from the typelib wrapper
- comtypes.server.automation.DualDispImplMixin, # other mixins
comtypes.server.connectionpoints.ConnectableObjectMixin,
):
Modified: ctypes/trunk/comtypes/comtypes/test/runtests.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/test/runtests.py (original)
+++ ctypes/trunk/comtypes/comtypes/test/runtests.py Thu Apr 17 19:56:27 2008
@@ -2,4 +2,4 @@
import comtypes.test
if __name__ == "__main__":
- sys.exit(comtypes.test.run(sys.argv[1:]))
+ sys.exit(comtypes.test.main(comtypes.test))
Modified: ctypes/trunk/comtypes/comtypes/test/test_collections.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/test/test_collections.py (original)
+++ ctypes/trunk/comtypes/comtypes/test/test_collections.py Thu Apr 17 19:56:27 2008
@@ -2,6 +2,8 @@
from comtypes.client import CreateObject, GetModule #, Constants
from ctypes import ArgumentError
+from comtypes.test.find_memleak import find_memleak
+
class Test(unittest.TestCase):
def test_IEnumVARIANT(self):
@@ -59,5 +61,22 @@
cv.Reset()
self.failUnlessRaises(ArgumentError, lambda: cv[:])
+ def test_leaks(self):
+ # The XP firewall manager.
+ fwmgr = CreateObject('HNetCfg.FwMgr')
+ # apps has a _NewEnum property that implements IEnumVARIANT
+ apps = fwmgr.LocalPolicy.CurrentProfile.AuthorizedApplications
+
+ def doit():
+ for item in iter(apps):
+ item.ProcessImageFileName
+ bytes = find_memleak(doit, (2, 20))
+ self.failIf(bytes, "Leaks %d bytes" % bytes)
+
+ def doit():
+ iter(apps).Next(99)
+ bytes = find_memleak(doit, (2, 20))
+ self.failIf(bytes, "Leaks %d bytes" % bytes)
+
if __name__ == "__main__":
unittest.main()
Modified: ctypes/trunk/comtypes/comtypes/test/test_createwrappers.py
==============================================================================
--- ctypes/trunk/comtypes/comtypes/test/test_createwrappers.py (original)
+++ ctypes/trunk/comtypes/comtypes/test/test_createwrappers.py Thu Apr 17 19:56:27 2008
@@ -78,6 +78,8 @@
print "ADD", path
add_test(path)
+for fname in glob.glob(os.path.join(common_progdir, r"Microsoft Shared\Speech\*.dll")):
+ add_test(fname)
for fname in glob.glob(os.path.join(sysdir, "*.dll")):
# these typelibs give errors:
More information about the Python-checkins
mailing list