[python-win32] Passing parameters to FoxPro COM methods

Richard Lawrence wyley.r at gmail.com
Mon Dec 27 19:30:28 CET 2010


[Posting again, as my original message does not seem to have arrived
at the list, perhaps because I was not subscribed...apologies for
double-posting if the original comes through after a delay.]

Hi all,

I have a few questions about passing parameters to methods on a
component built in Visual FoxPro 7.  I'm new to the list, and no COM
(or win32) expert -- I've tried to do my homework, but if I've missed
something, pointers to previous threads or documentation would be
greatly appreciated.

Some background:  I am basically using PythonCOM as the first step in
porting the functions provided by this component to a Unix
environment.  I am running Python 2.6 for Windows with the win32com
and related packages in Wine under Ubuntu.  The component basically
takes the form of a single FoxPro class in a DLL.  Instances of this
class have members that are instances of various other classes, but I
don't think those classes can be directly instantiated (i.e., they are
not themselves COM components exposed by the DLL).  I need to be able
to pass parameters to methods on these member objects.

For example, suppose the component is of class C and one of its
members, d, is an instance of class D; I need to be able to do
something like:

c = win32com.client.Dispatch("C")
c.d.some_method(param1, param2)

I have had some trouble getting PythonCOM to do this.  My problems and
questions are:

1) Regarding early binding: makepy.py doesn't seem to be able to get
the right interfaces from the DLL.  It doesn't seem to be able to
tell, for example, that d.some_method accepts two parameters (and it
assumes it accepts zero).  Therefore my attempts to use early binding
have been met with either COM errors (didn't pass enough arguments to
c.d.some_method) or TypeErrors (the generated module expected
some_method to take zero non-self arguments, but was passed two).
So...

1a) Is there perhaps something I'm missing about makepy?  I don't know
too much about what kind of type information is in the DLL/TLB; is it
possible that there is type information in there that I have to clue
makepy into other than simply having it introspect the DLL in the
standard way?

1b) If not, I might be able to get the DLL rebuilt with more type
information.  This article [1] seems to indicate that FoxPro supports
both early and late binding.  Does anyone have any tips for how to
recompile a Foxpro component such that its interfaces will be
correctly understood by makepy?

2) Regarding late binding: the way that attributes are looked up in
win32com.client.dynamic.CDispatch.__getattr__ seems not to play nicely
with Foxpro's way of responding to queries about the interface.  I
think what's happening is that __getattr__('some_method') attempts
first to call Invoke with pythoncom.INVOKE_PROPERTYGET as the
invocation type.  As the win32com documentation indicates sometimes
happens, Foxpro seems to respond to this by *calling* the method.
This means that if, say, some_method returns a string, then a call
like:

c.d.some_method(param1, param2)

blows up because __getattr__('some_method') returns a string value
that results from calling some_method, rather than a reference to the
method, so I get a TypeError to the effect that a string value is not
callable; whereas

c.d.some_method

actually calls the method and returns a value, but of course I can't
pass the call any parameters.

I have successfully managed to pass parameters to such methods by
calling Invoke() directly, with the parameters as extra positional
arguments, like so:

d_disp_interface = d._oleobj_.QueryInterface(pythoncom.IID_IDispatch)
some_method_id = d_disp_interface.GetIDsForNames('some_method')
the_value_I_seek = d_disp_interface.Invoke(some_method_id, 0,
pythoncom.DISPATCH_METHOD, 1, param1, param2)

This seems to work but is cumbersome; I am clearly not getting the
advantages that the high-level win32com.client interface is supposed
to provide.  So my question here is:

2a) If I am forced to use late binding, what's the best way to deal
with this issue, so that I can say things like c.d.some_method(param1,
param2) without errors?  Should I subclass CDispatch and override
__getattr__?  Or is there some way of providing CDispatch itself with
some hints about which attributes of (sometimes deeply nested) members
on the component are methods, and how many parameters they take?

I know this is a long post, but I've had a hard time finding
information about these issues, and wanted to provide as many details
as I could (for my own sake as well as posterity's).  Thanks for any
help you all can provide!

Best,
Richard

[1] http://msdn.microsoft.com/en-us/library/2c0y4cce(v=vs.71).aspx


More information about the python-win32 mailing list