[comtypes-users] Using a COMObject from a client more than once
Hi. In our project, we communicate with Microsoft SAPI 4 speech synthesisers using COM. When we want to speak data, we must provide an object which can receive events. (The IConnectionPoint* interfaces are not used.) Following is a rough, very simplified outline of the code: class SynthDriverBufSink(COMObject): _com_interfaces_ = [ITTSBufNotifySink] ... class SynthDriver(object): def __init__(self): self._ttsCentral = ... self._bufSink=SynthDriverBufSink() ... def performSpeak(self, text): ... self._ttsCentral.TextData(..., text, self._bufSink, ITTSBufNotifySink._iid_) _ttsCentral.TextData accepts a pointer to IUnknown (this is defined in its interface), as well as the iid of the ITTSBufNotifySink interface. The issue is that self._bufSink is created at instantiation, but is used in many calls to performSpeak. In comtypes 0.6.1, this was fine. However, in 0.6.2, when the ref count of a COMObject hits 0, the _com_pointers_ dict gets cleared to avoid a memory leak (svn r544). This means that the first call to performSpeak is fine. However, after this call completes, the ref count on self._bufSink will drop to 0, _com_pointers_ will be cleared and subsequent calls will fail to get the appropriate pointer. We've fixed this by never holding the underlying COMObject. In the constructor, we do: self._bufSink=SynthDriverBufSink().QueryInterface(ITTSBufNotifySink) This way, the pointer will AddRef and keep the underlying COMObject alive and will Release it when the pointer gets garbage collected. Despite the solution, this raises the question: Are we supposed to never maintain a long-lasting reference to an underlying COMObject? That is, was it always intended that a COMObject should never be held directly? In C++, one usually has the ref count start at 1, rather than 0. I understand this would present challenges in Python, as you don't know when to clean up the object. However, it'd be good to have some policy documentation on this scenario. Jamie -- James Teh Email/MSN Messenger/Jabber: ja...@jantrid.net Web site: http://www.jantrid.net/ -- SOLARIS 10 is the OS for Data Centers - provides features such as DTrace, Predictive Self Healing and Award Winning ZFS. Get Solaris 10 NOW http://p.sf.net/sfu/solaris-dev2dev ___ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users
[comtypes-users] __del__ called more than once on a comtypes COM POINTER object
Hi Thomas, In NVDA, we sometimes see access violation and vtable errors in __del__ on comtypes COM POINTER objects and intermittant crashes. I eventually figured that this might relate to Release() being called too many times. I then discovered that __del__ on these objects is sometimes called more than once. (We never call __del__ ourselves, so this is happening elsewhere.) As I understand it, Python should only ever call it once. I discovered this using the following rather nasty monkey patch before any COM objects are used: from comtypes import _compointer_base _cpbDel = _compointer_base.__del__ def newCpbDel(self): assert not hasattr(self, _deleted), compointer already deleted _cpbDel(self) self._deleted = True newCpbDel.__name__ = __del__ _compointer_base.__del__ = newCpbDel del _compointer_base This assertion does get raised. While I have come up with an exact set of steps to reproduce with NVDA and Firefox, I haven't yet managed to narrow it down to a programmatic test case due to the sheer number of interactions and code paths. I can tell you that we use QueryInterface quite a bit if that helps in any way. Can you think of any reason this might be happening? Is there any code in the ctypes POINTER type that calls __del__? Thanks. Jamie -- James Teh Email/MSN Messenger/Jabber: ja...@jantrid.net Web site: http://www.jantrid.net/ -- Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july ___ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users
[comtypes-users] comtypes.GUID._CoTaskMemFree: return type should be void
Hi Thomas, In GUID.py, _CoTaskMemFree is defined as oledll.ole32.CoTaskMemFree. While oledll is fine for most ole32 functions (as they return HRESULT), CoTaskMemFree is an exception and has a return type of void. In Windows 7, it seems that this does matter; the return value is sometimes -65535, which raises an exception due to a non-0 HRESULT. This is similar to the issue with ITypeLib::ReleaseTLibAttr. Btw, I saw this exception as a result of line 44 (in GUID.__unicode__): _CoTaskMemFree(p) I have attached a patch to fix this. Thanks. Jamie -- James Teh Email/MSN Messenger/Jabber: ja...@jantrid.net Web site: http://www.jantrid.net/ Index: comtypes/GUID.py === --- comtypes/GUID.py(revision 537) +++ comtypes/GUID.py(working copy) @@ -15,7 +15,7 @@ _ole32 = oledll.ole32 _StringFromCLSID = _ole32.StringFromCLSID -_CoTaskMemFree = _ole32.CoTaskMemFree +_CoTaskMemFree = windll.ole32.CoTaskMemFree _ProgIDFromCLSID = _ole32.ProgIDFromCLSID _CLSIDFromString = _ole32.CLSIDFromString _CLSIDFromProgID = _ole32.CLSIDFromProgID -- Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july___ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users
[comtypes-users] New release?
Hi Thomas, Any chance of a release some time soon? We're going to make a release of our software (NVDA) within the next few months, which uses comtypes heavily, and it'd be great to have some of the cool stuff in trunk (IServiceProvider, GetActiveObject with dynamic parameter, CoCreateInstance, etc.) in our new release. If there are other changes pending before you're willing to make a release, I understand, but thought I'd ask anyway. Jamie -- James Teh Email/MSN Messenger/Jabber: ja...@jantrid.net Web site: http://www.jantrid.net/ -- Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july ___ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users
Re: [comtypes-users] comtypes.server.IClassFactory.CreateInstance
On 5/08/2009 5:55 AM, Thomas Heller wrote: So, I have now in svn implemented the following: - Fixed the IClassFactory::CreateInstance method - Implemented a Pythonic interface for it, also including the nice 'dynamic=False' parameter. This is (almost) what I was looking for. Thanks! However, there is one issue. Currently, CreateInstance always tries to return the best interface, even if the interface was explicitly specified. In my case, I want a specific interface, but due to the fact that the typelib is not registered on the system, comtypes ends up returning a dispatch, which is not what I want. I've attached a patch against svn trunk to fix this. Thanks. Jamie -- James Teh Email/MSN Messenger/Jabber: ja...@jantrid.net Web site: http://www.jantrid.net/ Index: comtypes/server/__init__.py === --- comtypes/server/__init__.py (revision 531) +++ comtypes/server/__init__.py (working copy) @@ -16,14 +16,20 @@ if dynamic: if interface is not None: raise ValueError(interface and dynamic are mutually exclusive) -interface = comtypes.automation.IDispatch +realInterface = comtypes.automation.IDispatch elif interface is None: -interface = comtypes.IUnknown -obj = ctypes.POINTER(interface)() -self.__com_CreateInstance(punkouter, interface._iid_, ctypes.byref(obj)) +realInterface = comtypes.IUnknown +else: +realInterface = interface +obj = ctypes.POINTER(realInterface)() +self.__com_CreateInstance(punkouter, realInterface._iid_, ctypes.byref(obj)) if dynamic: return comtypes.client.dynamic.Dispatch(obj) -return comtypes.client.GetBestInterface(obj) +elif interface is None: +# An interface was not specified, so return the best. +return comtypes.client.GetBestInterface(obj) +# An interface was specified and obj is already that interface. +return obj ##class IExternalConnection(IUnknown): ##_iid_ = GUID({0019---C000-0046}) -- Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july___ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users
[comtypes-users] comtypes.server.IClassFactory.CreateInstance
Hi all, I've had cause to instantiate a COM class which is not registered on the system. To do this, one uses DllGetClassObject on the dll and then calls CreateInstance on the resulting IClassFactory. IClassFactory::CreateInstance is defined as: HRESULT CreateInstance( [in] IUnknown *pUnkOuter, [in] REFIID riid, [out] void **ppvObject ); However, in comtypes.server.IClassFactory, CreateInstance is defined as follows: _methods_ = [ comtypes.STDMETHOD(comtypes.HRESULT, CreateInstance, [ctypes.c_int, ctypes.POINTER(comtypes.GUID), ctypes.POINTER(ctypes.c_ulong)]), ... The final parameter being declared as c_ulong makes life a little painful. In order to use it, you have to do something like: instance = ctypes.c_ulong() factory.CreateInstance(0, interface._iid_, ctypes.byref(instance)) instance = ctypes.POINTER(interface)(instance.value) First of all, is there a reason that last parameter is c_ulong instead of c_void_p or the like? Second, is there any chance we could make this more Pythonic like the recent IServiceProvider.QueryInterface? Something like: instance = factory.CreateInstance(interface=interface) I'm curious as to how frequently this is already used, as such a change would break existing usage. Jamie -- James Teh Email/MSN Messenger/Jabber: ja...@jantrid.net Web site: http://www.jantrid.net/ -- Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july ___ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users
[comtypes-users] comtypes.client.GetActiveObject: dynamic parameter?
Hi all, Is there any chance that a dynamic parameter can be added to comtypes.client.GetActiveObject? This would do the same as the dynamic parameter to CreateObject. So, instead of: instance = comtypes.client.dynamic.Dispatch(comtypes.client.GetActiveObject(progid, interface=comtypes.automation.IDispatch)) one could do: instance = comtypes.client.GetActiveObject(progid, dynamic=True) Thanks. Jamie -- James Teh Email/MSN Messenger/Jabber: ja...@jantrid.net Web site: http://www.jantrid.net/ -- Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july ___ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users
[comtypes-users] this parameter to COM event functions
Hi all, I am a little confused about the this parameter to COM events. When one wants to receive COM events, one does something like the following: self._advise = comtypes.client.GetEvents(self._server, Sink()) where the Sink class has methods such as: def onEvent(self, this, arg1, arg2): ... However, it seems that there has recently been a change in the way this is handled. (I am not sure what version of comtypes this occurred in, but I suspect 0.5.1.) It seems that the name this is somehow special. If the exact parameter name this is not present as the first argument, the event seems to work fine without it. For example, the following works: def onEvent(self, arg1, arg2): However, this does not work: def onEvent(self, this, arg2): It would seem that the this parameter is now optional. Unfortunately, with another COM server, if this is present at all, the event function is not fired. Can anyone provide some clarification as to the status of the this parameter in comtypes 0.5.2? Is this now optional? Is the name this special? Thanks. -- James Teh Email/MSN Messenger/Jabber: [EMAIL PROTECTED] Web site: http://www.jantrid.net/ - This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100url=/ ___ comtypes-users mailing list comtypes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/comtypes-users