Re: [comtypes-users] Problem calling method
Hi, Recently we noticed the same problem with our project. We access the MS Word object model via IDispatch, but there is a GetPoint method which takes left, top, hight and width as byref arguments. As comtypes doesn't support vt_byref out of the box, our first idea was to rewrite the code for VARIANT._set_value(), and provide comtypes with a patch. However, looking at VARIANT._set_value(): There are lots of returns all the way through the function, so its clear it would have to be rewritten almost from the ground up. And since I'm not too skilled with all of the VARIANT types, I don't want to break any existing logic. So, what we currently do, is when our project imports comtypes at initialization time, we do the following: #Monkey patch comtypes to support byref in variants from comtypes.automation import VARIANT, VT_BYREF from ctypes import cast, c_void_p from _ctypes import _Pointer oldVARIANT_value_fset=VARIANT.value.fset def newVARIANT_value_fset(self,value): realValue=value if isinstance(value,_Pointer): try: value=value.contents except (NameError,AttributeError): pass oldVARIANT_value_fset(self,value) if realValue is not value: self.vt|=VT_BYREF self._.c_void_p=cast(realValue,c_void_p) VARIANT.value=property(VARIANT.value.fget,newVARIANT_value_fset,VARIANT.value.fdel) So, from then on, when ever passing an instance of a POINTER of a ctypes type, comtypes will automatically treet the value as byref. Some example code for GetPoint: from ctypes import c_long, pointer rangeLeft=c_long() rangeTop=c_long() rangeWidth=c_long() rangeHeight=c_long() self.obj.WinwordWindowObject.getPoint(pointer(rangeLeft),pointer(rangeTop),pointer(rangeWidth),pointer(rangeHeight),self._rangeObj) I would probably prefer that we use ctypes.byref, rather than ctypes.POINTER, as the name relates better to what its doing. But, ctypes.byref(x) yields an object who's type is something like type(cArgObject), which I can't find anywhere in ctypes or _ctypes. So, it would be a little hard for VARIANT._set_value to properly identify that value was a byref. Interestingly enough though, if comtypes compiles the actual COM interfaces for the MS Word object model, POINTER is used anyway, so I guess POINTER is ok. Mick On 13/02/2010 10:48 AM, Pablo Bianucci wrote: > Hi Thomas! > > On Fri, 12 Feb 2010, Thomas Heller wrote: > >> Exactly. I cannot provide a patch, but here's a code snippet that creates >> such a beast: > > Yes! It works!! > > This is the final working snippet: > > > travel = c_float(0) > v = VARIANT() > v._.c_void_p = cast(pointer(travel), c_void_p) > v.vt = VT_BYREF | VT_R4 > > mode = c_int(0) > vm = VARIANT() > vm._.c_void_p = cast(pointer(mode), c_void_p) > vm.vt = VT_BYREF | VT_I4 > > try: > piezo1.GetMaxTravel(APTPiezoLib.CHAN1_ID, v) > piezo1.GetControlMode(APTPiezoLib.CHAN1_ID, vm) > except Exception, e: > print "Exception:", e > print travel.value, mode.value > > > If you are not careful when setting the types you get a "Type Mismatch" > error (even though the protoypes in the help were the same, I had to use > different types for the two funcions there). > > I wonder why you can't integrate this into the package. I'm fine as this, > as this will let me write the program I need, but it would be more user > friendly to be able use pointers as arguments for the method invocation. > But I don't understand COM internals, so it could be that implementing > that could lead to other problems. > > Thank you very much for your help! > > Bye& Good Luck! > > Pablo. > > P.S.: If you visit Canada and stay at a city I happen to be living in, > consider yourself invited to a drink. ;-) > > > -- > 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 -- Michael Curran President, NV Access Inc Email: m...@nvaccess.org Website: www.nvaccess.org ABN 61773362390. -- 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
Re: [comtypes-users] Problem calling method
Hi Thomas! On Fri, 12 Feb 2010, Thomas Heller wrote: > Exactly. I cannot provide a patch, but here's a code snippet that creates > such a beast: Yes! It works!! This is the final working snippet: travel = c_float(0) v = VARIANT() v._.c_void_p = cast(pointer(travel), c_void_p) v.vt = VT_BYREF | VT_R4 mode = c_int(0) vm = VARIANT() vm._.c_void_p = cast(pointer(mode), c_void_p) vm.vt = VT_BYREF | VT_I4 try: piezo1.GetMaxTravel(APTPiezoLib.CHAN1_ID, v) piezo1.GetControlMode(APTPiezoLib.CHAN1_ID, vm) except Exception, e: print "Exception:", e print travel.value, mode.value If you are not careful when setting the types you get a "Type Mismatch" error (even though the protoypes in the help were the same, I had to use different types for the two funcions there). I wonder why you can't integrate this into the package. I'm fine as this, as this will let me write the program I need, but it would be more user friendly to be able use pointers as arguments for the method invocation. But I don't understand COM internals, so it could be that implementing that could lead to other problems. Thank you very much for your help! Bye & Good Luck! Pablo. P.S.: If you visit Canada and stay at a city I happen to be living in, consider yourself invited to a drink. ;-) -- 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
Re: [comtypes-users] Problem calling method
Am 12.02.2010 20:24, schrieb Pablo Bianucci: > Hi Thomas! > > On Fri, 12 Feb 2010, Pablo Bianucci wrote: > >> Exception: Cannot put in VARIANT > > The problem seems to be that the initialization of VARIANT does not know > what to do with a pointer type. I think that VARIANT could be extended to > handle those: > > Get the value of the pointer (no the contents but the actual address), > store that as the content of the VARIANT instance and then set the > VT_BYREF flag. Do you think that would work? Exactly. I cannot provide a patch, but here's a code snippet that creates such a beast: from comtypes.automation import * mode = c_int(42) # our variable v = VARIANT() v._.c_void_p = cast(pointer(mode), c_void_p) v.vt = VT_BYREF | VT_I4 print v # prints 'VARIANT(vt=0x4003, byref(42))' You could use this stuff and pass it to Invoke. I assume that is will be changed after the call. Pretty straightforward to retrieve the result; VARIANT contains code for that. Since the VARIANT is a kind of pointer, I have chosen the indexing to acces the contained value: print v # prints 'VARIANT(vt=0x4003, byref(42))' print v[0] # prints '42' > What I don't see how to do is how to get the address pointed to as a plain > number. cast does that for you, without worring about the actual address. -- Thanks, Thomas -- 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
Re: [comtypes-users] Problem calling method
Hi Thomas! On Fri, 12 Feb 2010, Pablo Bianucci wrote: > Exception: Cannot put in VARIANT The problem seems to be that the initialization of VARIANT does not know what to do with a pointer type. I think that VARIANT could be extended to handle those: Get the value of the pointer (no the contents but the actual address), store that as the content of the VARIANT instance and then set the VT_BYREF flag. Do you think that would work? What I don't see how to do is how to get the address pointed to as a plain number. Bye & Good Luck! Pablo. -- 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
Re: [comtypes-users] Problem calling method
Hi Thomas! On Fri, 12 Feb 2010, Thomas Heller wrote: The first snip does not work. These are the errors: > print ptr.GetControlMode(chanid) # try to leave out the plMode parameter Exception: (-2147352561, 'Parameter not optional.', (None, None, None, 0, None)) > print ptr.GetControlMode(chanid, 0) # pass a number for plMode... Exception: (-2147352571, 'Type mismatch.', ('TypeError: Parameter 1', (0, 0))) > If nonthing of the above works, I guess you would have to pass the second > parameter > by reference. The basic code would have to look something like this; it > is basically what I assume that VB does: I've tried that by doing the simplistic thing: mode = c_int(0) piezo1.GetMaxTravel(APTPiezoLib.CHAN1_ID, byref(mode)) And I get: Exception: Cannot put in VARIANT I guess that means I do need that pass_by_reference() function to do some massaging of types. > Ok, but what is this pass_by_reference() function? > > It should take the argument (a ctypes c_int instance, for example), > and convert to something that will eventually, in the Invoke call, > used as BYREF VARIANT argument. > > I'll try to come up with some ideas for that if the first code snippet > above really fails. Is there anything you would recommend me to read to try to get some ideas on my own? Thanks for your help! Bye & Good Luck! Pablo B. -- 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
Re: [comtypes-users] Problem calling method
Am 11.02.2010 02:32, schrieb Pablo Bianucci: [...] >>From the documentation of this control, I get this prototype (I don't know if > that's the right name): > > --- > Function GetControlMode(lChanID As Long, plMode As Long) As Long > > > Parameters > > lChanID - the channel identifier > plMode - returns the control loop feedback status > --- > > I found this other funcion, that seems similar and has a code example: > > --- > Function GetMaxTravel(lChanID As Long, plMaxTravel As Long) As Long > > > Parameters > > lChanID - the channel identifier > plMaxTravel - returns the maximum travel (in microns) > > Example: > > Private Sub cmdGetTravel_Click() > > Dim sngMaxTravel As Single > > MG17Piezo1.GetMaxTravel CHAN1_ID, sngMaxTravel > > ' inform user of piezo max travel > MsgBox "Maximum travel of piezo = " & sngMaxTravel > --- > > Does this help? Well, what you could try out are these code snippets in Python: chanid = 42 # or whatever this needs to be... print ptr.GetControlMode(chanid) # try to leave out the plMode parameter print ptr.GetControlMode(chanid, 0) # pass a number for plMode... print ptr.GetMaxTravle(chanid) print ptr.GetMaxTravel(chanid, 0) If nonthing of the above works, I guess you would have to pass the second parameter by reference. The basic code would have to look something like this; it is basically what I assume that VB does: # create a variable containing the 'control loop feedback status', # initialized to some value mode = c_int(0) # Call the function, passing the VALUE of chanid, # and a REFERENCE to the 'mode' variable. print ptr.GetControlMode(chanid, pass_by_reference(mode)) # The result of the function call should now have been printed, # and the 'mode' variable should contain an updated value: print mode.value Ok, but what is this pass_by_reference() function? It should take the argument (a ctypes c_int instance, for example), and convert to something that will eventually, in the Invoke call, used as BYREF VARIANT argument. I'll try to come up with some ideas for that if the first code snippet above really fails. > >> However, it could be that comtypes is not able to call this method... > > I hope not! (crossing fingers... :-)) We'll see. -- Thanks, Thomas -- 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