[python-win32] win32com gencache InvokeTypes and OUT/ByRef parameters
Hibiki Kanzaki
hibikikanzaki at gmail.com
Thu Jun 11 22:58:11 CEST 2009
I am using a COM library from Python. The methods
have OUT parameters, so I am using the gencache/makepy
facility of win32com. When it generates the wrapper
files, there are function definitions like this one
(this is for accessing Visual SourceSafe COM Automation)
# Result is of type IVSSItem
# The method VSSItem is actually a property, but must be used as a
method to correctly pass the arguments
def VSSItem(self, Spec=defaultNamedNotOptArg, Deleted=False):
ret = self._oleobj_.InvokeTypes(6, LCID, 2, (9, 0), ((8, 1), (11, 49)),Spec
, Deleted, ppIVSSItem)
if ret is not None:
ret = Dispatch(ret, u'VSSItem', '{2A0DE0E7-2E9F-11D0-9236-00AA00A1EB95}')
return ret
When VSSItem() is called, it gets an error that ppVSSItem
is not defined... and as far as I can tell that is correct,
I do not see anything anywhere in the wrapper files where
it appears to define any "ppIVSSItem". In this particular
case, I can manually edit that file and simply remove that
last argument, and then it works fine. That code is in a
wrapper for VSSDatabase (IVSSDatabase). When the VSSItem
object is created, a new file IVSSItem.py is created which
has the same problem-- InvokeTypes is passed arguments
which are names of variables which do not seem to exist.
I am not sure if I can get away with editing files
this way... especially in cases where the method does
not simply have one trailing OUT parameter. it would
be nice if I did not, especially since I do not get
all the wrappers at once-- they are generated only
when I try to instantiate another type of COM object
(indirectly, by calling methods of the other objects).
I am curious what is going on here... it looks like maybe
the wrapper is generated by MakeDispatchFuncMethod in
win32com/client/build.py, by code which looks like this:
retDesc = fdesc[8][:2]
argsDesc = tuple([what[:2] for what in fdesc[2]])
# The runtime translation of the return types is expensive, so when
we know the
# return type of the function, there is no need to check the type at runtime.
# To qualify, this function must return a "simple" type, and have no
byref args.
# Check if we have byrefs or anything in the args which mean we
still need a translate.
param_flags = [what[1] for what in fdesc[2]]
bad_params = [flag for flag in param_flags if flag &
(pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FRETVAL)!=0]
s = None
if len(bad_params)==0 and len(retDesc)==2 and retDesc[1]==0:
rd = retDesc[0]
if rd in NoTranslateMap:
s = '%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s, %s%s)'
% (linePrefix, id, fdesc[4], retDesc, argsDesc, _BuildArgList(fdesc,
names))
elif rd in [pythoncom.VT_DISPATCH, pythoncom.VT_UNKNOWN]:
s = '%s\tret = self._oleobj_.InvokeTypes(%d, LCID, %s, %s,
%s%s)\n' % (linePrefix, id, fdesc[4], retDesc, repr(argsDesc),
_BuildArgList(fdesc, names))
s = s + '%s\tif ret is not None:\n' % (linePrefix,)
if rd == pythoncom.VT_UNKNOWN:
s = s + "%s\t\t# See if this IUnknown is really an IDispatch\n" %
(linePrefix,)
s = s + "%s\t\ttry:\n" % (linePrefix,)
s = s + "%s\t\t\tret =
ret.QueryInterface(pythoncom.IID_IDispatch)\n" % (linePrefix,)
s = s + "%s\t\texcept pythoncom.error:\n" % (linePrefix,)
s = s + "%s\t\t\treturn ret\n" % (linePrefix,)
s = s + '%s\t\tret = Dispatch(ret, %s, %s)\n' %
(linePrefix,repr(name), resclsid)
s = s + '%s\treturn ret' % (linePrefix)
elif rd == pythoncom.VT_BSTR:
s = "%s\t# Result is a Unicode object\n" % (linePrefix,)
s = s + '%s\treturn self._oleobj_.InvokeTypes(%d, LCID, %s, %s,
%s%s)' % (linePrefix, id, fdesc[4], retDesc, repr(argsDesc),
_BuildArgList(fdesc, names))
# else s remains None
This code is opaque for me since I have no familiarity
with the code, or what is the correct behavior...
By the way this is build213 running with Python 2.6.
I have the same problem with build212.
More information about the python-win32
mailing list