I must admit I don't know how to fully test my implementation. I also
have at least one bug related to strings, which the test below will
demonstrate. I am soliciting any help I can get to solve the general
case. Or, failing that, I'm wondering if a less-general patch would be
accepted (that patch is described at the end of this
Yeah, such a patch certainly *would* be accepted, once we bash it into shape
:)
[code]
class Variant: pass #Not its final form. :)
point = Variant() #This arg is specified as Variant (not byref)
point.__VT__ = 5
point.__VAR__ = (1, 1, 0)
I think I'd prefer the attributes named differently, but I'm not sure
exactly what :). _com_variant_type_ is kinda consistent with the other
attributes we support. _com_variant_value_ is probably reasonable too.
Users generally won't see the names, assuming we define a sensible
constructor.
The implementation is in PyCom_VariantFromPyObject() in oleargs.cpp.
This code gets called in all cases that use Invoke. And, in the case of
InvokeTypes, it gets called if the TYPEDESC calls for VT_VARIANT or
VT_VARIANT | VT_BYREF (which covers everything for autocad, and the one
other case I found from a quick google for similar issues.)
Yeah, that sounds quite reasonable.
[code: forgive any of my newness that shows thru]
if ( PyInstance_Check(obj) PyObject_HasAttrString(obj, __VT__)
PyObject_HasAttrString(obj, __VAR__) )
{
PyObject* reqdType = PyObject_GetAttrString(obj, __VT__);
if (!reqdType) return FALSE;
VARENUM rawVT = (VARENUM)PyInt_AsLong(reqdType);
PyObject* obuse = PyObject_GetAttrString(obj, __VAR__);
As a minor nit, I'd probably avoid the HasAttrString checks above, and just
handle the GetAttrString failing. Behind the scenes, HasAttrsString is just
going to fetch the attribute and handle any exceptions anyway, so this means
we are fetching them twice.
if ( PySequence_Check(obuse) )
{
V_ARRAY(var) = NULL; // not a valid, existing array.
ok = PyCom_SAFEARRAYFromPyObject(obuse, V_ARRAY(var), rawVT);
V_VT(var) = VT_ARRAY | rawVT;
}
else
{
PythonOleArgHelper helper;
helper.m_reqdType = rawVT;
V_VT(var) = rawVT;
ok = helper.MakeObjToVariant(obuse, var);
The problem may well be your use of PySequence_Check() - that will succeed
for a string. You are then likely to end up with a VT_UI8 array. I think
you should *always* defer to MakeObjToVariant - that function will check the
VT, and if an array is requested it will do the right thing - ie, the
variant-type should *always* drive the conversion process in this case,
rather than the object value.
So in the case of InvokeTypes, this can seem strange. InvokeTypes will
instantiate a PythonOleArgHelper. If TYPEDESC calls for VT_VARIANT
(byref or not), the ArgHelper delegates to PyCom_VariantFromPyObject().
If PyCom_VariantFromPyObject() detects an instance of class Variant,
it will instantiate a *different* ArgHelper (unless the argument is a
sequence, in which case it delegates to PyCom_SAFEARRAYFromPyObject()).
Yeah, that does seem strange, but is likely to work :) The arg helper
objects really are just state for the conversion - once the variant type
is set the helpers aren't used.
It will likely take me awhile to figure through the rest of this on my
own. In the meantime, this code could be pared down to solve a less
general case than Mark describes above: the Variant() class could be
used *just* so that a user could build an array of objects typed to
their choosing. I think this would still be useful, and it would likely
be forward-compatible with a solution for the general case. So...if
nobody else has a pressing need for this, or time to help with it, (Mark
other CVS committers) would you accept a less general patch?
Yep, I think this is looking quite reasonable. Regarding testing, the best
thing is probably to try and use win32com\test\testvb.py. If you have VB
and the pywin32 sources, you should be able to create the test DLL from the
com\TestSources\PyCOMVBTest directory. testvb.py exercises *lots* of
different variant types, so somehow arranging (by copy-paste if necessary)
for those tests to be called with a new Variant object would be excellent.
If you don't have VB, let me know and I will send you a compliled DLL.
Cheers,
Mark
___
Python-win32 mailing list
Python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32