Mark Hammond wrote:
>>     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.
Ah -- the lightbulb above my head is now lit.  Thank you!

> 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.
Got the tests, passed the tests!  The original testvb.py also passes, so 
I can't have messed anything up *too* much!  :)

I don't want to post such long code, so I'm hosting it.  If the links 
don't work for any interested party, please just email me and I'll get 
you a copy.  I'm quite enjoying this learning experience and am open to 
all suggestions.

Test file:
http://www.originalrog.org/testvb_variantclass.py

My first try at class Variant (and some helpers):
http://www.originalrog.org/VariantUtils.py

That is the class definition which passed the tests.  I hope a new-style 
class is okay; I figured it would be, given the python versions for 
which pywin32 "binaries" are distributed.  If not, I don't think there's 
anything that can't be rewritten in classic style.

A brief interactive session showing some class behaviour:
http://www.originalrog.org/variantclass_interactive.txt

The C++ implementation is below.  I erased some of this 
thread...so...context:  this is in oleargs.cpp in 
PyCom_VariantFromPyObject().  I put this clause just before the 
PySequence_Check() clause instead of at the top; figure it won't be used 
as often as the other clauses.

[code]
else if (strcmp(obj->ob_type->ob_type->tp_name, "VariantBase") == 0)
{
    PyObject* typeAttr = PyString_FromString("_com_variant_type_");
    PyObject* valAttr = PyString_FromString("_com_variant_value_");

    if (!(typeAttr && valAttr))
       return FALSE;

    PyObject* reqdType = PyObject_GenericGetAttr(obj, typeAttr);
    if (!reqdType)
       return FALSE;

    VARENUM rawVT = (VARENUM)PyInt_AsLong(reqdType);
    PyObject* obuse = PyObject_GenericGetAttr(obj, valAttr);
    if (!obuse)
    {
       Py_XDECREF(reqdType);
       return FALSE;
    }
    PythonOleArgHelper helper;
    helper.m_reqdType = V_VT(var) = rawVT;
    helper.MakeObjToVariant(obuse, var);
    Py_XDECREF(reqdType);
    Py_XDECREF(obuse);
}
// NOTE:  PySequence_Check may return true for instance objects,
...
[/code]

Cheers!
-Dan Glassman
_______________________________________________
Python-win32 mailing list
Python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to