Ticket URL: <
http://trac.wxwidgets.org/ticket/14296>
#14296: Add support for conversion of wxVariant with "arrstring" type to OLE
VARIANT
-----------------------------------------------------------+----------------
Reporter: PB | Owner:
Type: defect | Status: new
Priority: normal | Milestone:
Component: wxMSW | Version: 2.9-svn
Keywords: wxVariant; VARIANT; wxArrayString; conversion | Blockedby:
Patch: 1 | Blocking:
-----------------------------------------------------------+----------------
I was surprised to find out that wxConvertVariantToOle() doesn't support
conversion of wxVariant with built-in "arrstring" type (contains
wxArrayString) to OLE Variant.
wxConvertOleToVariant() properly converts VARIANTs with VT_ARRAY and
VT_BSTR to wxVariant with "arrstring" type.
The current code for converting wxVariants with "list" type in
wxConvertVariantToOle() in <wx/src/msw/ole/oleutils.cpp> is
{{{
else if (type == wxT("list") || type == wxT("stringlist"))
{
oleVariant.vt = VT_VARIANT | VT_ARRAY;
SAFEARRAY *psa;
SAFEARRAYBOUND saBound;
VARIANTARG *pvargBase;
VARIANTARG *pvarg;
int i, j;
int iCount = variant.GetCount();
saBound.lLbound = 0;
saBound.cElements = iCount;
psa = SafeArrayCreate(VT_VARIANT, 1, &saBound);
if (psa == NULL)
return false;
SafeArrayAccessData(psa, (void**)&pvargBase);
pvarg = pvargBase;
for (i = 0; i < iCount; i++)
{
// copy each string in the list of strings
wxVariant eachVariant(variant[i]);
if (!wxConvertVariantToOle(eachVariant, * pvarg))
{
// memory failure: back out and free strings alloc'ed up
to
// now, and then the array itself.
pvarg = pvargBase;
for (j = 0; j < i; j++)
{
SysFreeString(pvarg->bstrVal);
pvarg++;
}
SafeArrayDestroy(psa);
return false;
}
pvarg++;
}
SafeArrayUnaccessData(psa);
oleVariant.parray = psa;
}
}}}
There's a few things I find a bit odd in the code above:
1. Can the wxVariant even have type "stringlist"? I don't think it
supports direct conversion from and to wxListString?
1. The code doesn't check if the individual wxVariants are not of "list"
type. I believe !SafeArrays can't contain VARIANTs with arrays.
1. It appears that the code somewhat assumes all items of the newly
created safe array are BSTRs and attempts to free them as such on error?
While harmless, it looks kind of weird to me, but it's probably all right.
My new code is very ugly, mainly for two reasons (aside from my inability
to produce elegant code):
1. I didn't want to split handling "list" and "arrstring" into two
entirely separate code paths, I believe they have enough in common.
Unfortunately, wxWariant with "arrstring" type has different interface for
accessing the individual items than when it has a list of wxVariants, so
there were few extra hoops.
1. There is a lot of error checking, it rarely adds to the beauty of
code, particularly when you can't use exceptions.
New code for conversion of wxVariant with "list" and "arrstring" type for
wxConvertVariantToOle() function
{{{
else if (type == wxT("list") || type == wxT("arrstring"))
{
SAFEARRAY *psa;
SAFEARRAYBOUND saBound;
bool isArrString = type == wxT("arrstring");
wxArrayString strings;
if (isArrString)
strings = variant.GetArrayString();
oleVariant.vt = (isArrString ? VT_BSTR : VT_VARIANT) | VT_ARRAY;
long lCount = isArrString ? strings.GetCount() :
variant.GetCount();
saBound.lLbound = 0;
saBound.cElements = lCount;
psa = SafeArrayCreate(isArrString ? VT_BSTR : VT_VARIANT, 1,
&saBound);
if (psa == NULL)
return false;
long i;
for (i = 0; i < lCount; i++)
{
if (isArrString)
{
wxBasicString bstr(strings[i]);
if ((BSTR)bstr != NULL || strings[i].empty()) // BSTR can
be NULL for empty strings
{
if (FAILED(SafeArrayPutElement(psa, &i, (BSTR)bstr)))
break;
} else
break; // out of memory when allocating wxBasicString?
}
else // list of wxVariants
{
VARIANT v;
HRESULT hr;
const wxVariant& eachVariant = variant[i];
// safe array elements can't contain another arrays
if (eachVariant.GetType() != wxT("list") &&
eachVariant.GetType() != wxT("arrstring")
&& wxConvertVariantToOle(eachVariant, v))
{
hr = SafeArrayPutElement(psa, &i, &v);
VariantClear(&v); // SafeArrayPutElement makes a copy
of an added element
if (FAILED(hr))
break;
} else
break; // couldn't convert from wxVariant
}
}
if (i < lCount) // the iteration was exited prematurely because of
an error
{
SafeArrayDestroy(psa);
wxLogError(wxT("wxAutomationObject::ConvertVariantToOle:
couldn't convert to safe array"));
return false;
}
oleVariant.parray = psa;
} // if (type == wxT("list") || type == wxT("arrstring"))
}}}
--
Ticket URL: <
http://trac.wxwidgets.org/ticket/14296>