Re: [comtypes-users] How to implement COM interface properly

2009-06-17 Thread Thomas Heller
px schrieb:
 Thanks Thomas! This was very helpful indeed.  Working great now :)
 
 Came across another problem trying to read back an unsigned byte buffer..
 I'm pretty stumped
 
 #COMMETHOD([], HRESULT, 'Read',
 #  ( ['out'], POINTER(c_ubyte), 'data' ),
 #  ( ['in'], c_int, 'len' ),
 #  ( ['out'], POINTER(c_int), 'actual' )),
 
 When I call Read(2048), I always just get 13 back for the data field (first
 element in returned tuple) but I actually expect more bytes.
 
 I took a shot at doing a ctypes style call, but when I try to make the call
   x.Read(byref(data), len, byref(actual))
 I get
   TypeError: call takes exactly 2 arguments (4 given)
 
 It seems that comtypes only wants the in 'len' parameter.
 
From the IDL:
 HRESULT Read(
 [out, size_is(length), length_is(*actual)] BYTE* data,
 [in] long length,
 [out] long* actual);

comtypes isn't able to handle the 'length_is(...)' attribute.  Besides,
the info from this attribute isn't present in the TLB at all.  So,
you should override the generated 'Read' method in this way,
which passes the pointer as 'in' argument, and later unpacks it:


   COMMETHOD([], HRESULT, 'Read',
 ( ['in'], POINTER(c_ubyte), 'data' ),
 ( ['in'], c_int, 'len' ),
 ( ['out'], POINTER(c_int), 'actual' )),
   ...]

   def Read(self, len):
   data = POINTER(c_ubyte)()
   actual = self._Read(byref(data), len)
   result = data[:actual]
   # I guess you need to free the memory here?
   # windll.ole32.CoTaskMemFree(data)
   return result

Thomas


--
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables unlimited
royalty-free distribution of the report engine for externally facing 
server and web deployment.
http://p.sf.net/sfu/businessobjects
___
comtypes-users mailing list
comtypes-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/comtypes-users


Re: [comtypes-users] Proposal to add IServiceProvider to comtypes

2009-06-17 Thread Michael Curran

Hi Thomas,

Your definition of IServiceProvider works perfect for me.

I am happy for it to go in comtypes/__init__.py, but for now though, 
again I have attached a servprov.py with your changes, plus 
testQueryService.py which is some code that shows how IServiceProvider 
can be used.
running testQueryService.py starts Internet Explorer, navigates to 
'about:blank', and query interface to IServiceProvider on the body 
element, and uses queryService to get to an IAccessible (MSAA) object.


Hope this code will be useful enough to be made in to a testcase.

Mick






On 17/06/2009 5:01 AM, Thomas Heller wrote:

Michael Curran schrieb:

Hi,

Attached is a module which contains a definition of the IServiceProvider
interface. This interface is provided as an interface on COM objects to
make it possible to switch to a different service, related to the
object. For example  given an IAccessible (MSAA) object, you can use its
IServiceProvider interface to get to other things such as an
IHTMLElement (when dealing with MSHTML), or IAccessible2 etc.
Info on this interface can be found at:
http://msdn.microsoft.com/en-us/library/cc678965%28VS.85%29.aspx


Generally, the interface seems simple enough (only one method)
and generic enough so that it is justified to add it to the
comtypes\__init__.py module.

It would also be great if you can supply a small code snippet that uses the
IServiceProvider.QueryService method, so that I can make a simple test
for it.


IServiceProvider is defined in servprov.idl in the Microsoft Platform SDK.

A part from providing a standard comtypes definition of the interface, I
have also overridden the QueryService method, to be a little more
pythonic, so that you can pass an interface as the second argument,
rather than just an IID, and then it actually returns an instance of
that interface, rather than just an IUnknown pointer.

I propose that this module (servprov.py) be added to comtypes, so that
others can make use of this, rather than having to code the definition
manually.

Note also that IServiceProvider is not included in any standard type
library that I know of, so defining this interface specifically is the
only way to use it.

Hopefully I have formatted the file suitably for inclusion.



# -*- coding: mbcs -*-
from ctypes import *
from comtypes import *

class IServiceProvider(IUnknown):
 _case_insensitive_ = True
 _iid_ = GUID('{6D5140C1-7436-11CE-8034-00AA006009FA}')
 _idlflags_ = []


I'd suggest to remove the _case_insensitive_ and _idlflags_ attributes.


 #Overridden QueryService to make it nicer to use (passing it an interface 
and it returns a pointer to that interface)
 def QueryService(self,serviceIID,interface):
 if not issubclass(interface,IUnknown):
 raise ValueError(interface argument must  be a COM interface)
 interfaceIID=interface._iid_
 if not isinstance(serviceIID,GUID):
 raise ValueError(serviceIID argument must be a GUID)
 p=self._QueryService(byref(serviceIID),byref(interfaceIID))
 return POINTER(interface)(p)


I think the issubclass tests can also be omitted.



IServiceProvider._methods_ = [
 COMMETHOD([], HRESULT, 'QueryService',
 ( ['in'], POINTER(GUID), 'guidService' ),
 ( ['in'], POINTER(GUID), 'riid' ),
 ( ['out'], POINTER(c_void_p), 'ppvObject' )),
 COMMETHOD([], HRESULT, 'RemoteQueryService',
 ( ['in'], POINTER(GUID), 'guidService' ),
 ( ['in'], POINTER(GUID), 'riid' ),
 ( ['out'], POINTER(POINTER(IUnknown)), 'ppvObject' )),
]


The definition for 'RemoteQueryService' must be removed.  The IServiceProvider
has only ONE method (the midl-compiler sometimes creates C/C++ wrapper methods
called Remote..., but I guess these have somehow to do with marshalling
or something like that).

All in all, this is how I would write this interface:

class IServiceProvider(IUnknown):
 _iid_ = GUID('{6D5140C1-7436-11CE-8034-00AA006009FA}')

 # Overridden QueryService to make it nicer to use (passing it an
 # interface and it returns a pointer to that interface)
 def QueryService(self, serviceIID, interface):
 p = POINTER(interface)()
 self._QueryService(byref(serviceIID), byref(interface._iid_), byref(p))
 return p

 _methods_ = [
 COMMETHOD([], HRESULT, 'QueryService',
   ( ['in'], POINTER(GUID), 'guidService' ),
   ( ['in'], POINTER(GUID), 'riid' ),
   ( ['in'], POINTER(c_void_p), 'ppvObject' ))
 ]

Does this work for you?

BTW:  The reason that the third parameter must be declared 'in' is that
still 'out' parameters are somewhat broken in comtypes.

# -*- coding: mbcs -*-
from ctypes import *
from comtypes import *

class IServiceProvider(IUnknown):
_iid_ = GUID('{6D5140C1-7436-11CE-8034-00AA006009FA}')

# Overridden QueryService to make it nicer to use (passing it an
# interface and it returns a