[comtypes-users] Using a COMObject from a client more than once

2010-02-10 Thread James Teh
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

2009-09-12 Thread James Teh
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

2009-09-01 Thread James Teh

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?

2009-08-08 Thread James Teh
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

2009-08-04 Thread James Teh

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

2009-07-31 Thread James Teh
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?

2009-07-31 Thread James Teh
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

2008-10-30 Thread James Teh
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