PDA

View Full Version : ActiveQt : Setting Currency properties of a QAxObject



drfitz
25th July 2012, 11:06
I'm accessing some third-party COM objects that have Currency/Decimal properties. ActiveQt supports the Currency (CY) type of COM, which is simply an int64, using qlonglong. For instance, an amount of $1.23 is saved as 12300. Reading such a currency property in a QAxObject is not a problem -- I simply divide by 10000 to get the real amount. However, setting such a property is a problem since the input is taken "at face value". Floating point numbers are converted to qlonglongs and cents are omitted in the conversion:


double value1 = 1.23;
qaxobject->setProperty("Amount", value1);
// property("Amount") returns 10000 = $1

// Multiplying by 10,000 beforehand therefore doesn't work either
qlonglong value2 = 12300; // trying again for $1.23
qaxobject->setProperty("Amount", value2);
// property("Amount") returns 123000000 = $12300

Is this because of the conversion to QVariant? If so, does anybody know a way around setProperty/dynamicCall to set the property in its native type? Or are the third-party components at fault? Thanks a lot.
(Using Qt4.8.2, Visual Studio 2010)

ChrisW67
26th July 2012, 02:19
Try:


qlonglong value2 = 12300;
qaxobject->setProperty("Amount", QVariant(value2));

I suspect you are getting a QVariant(int) (because the value will fit) instead of QVariant(qlonglong) inside the ActiveQt marhsalling code which then fails to match it to the CY field properly.

drfitz
26th July 2012, 09:48
I tried that. Unfortunately, it still returns 123000000.

drfitz
26th July 2012, 16:43
Digging a bit deeper, I found the following in Qt's qaxtypes.cpp, in the method QVariantToVARIANT(..., bool out = false). QVariantToVARIANT is used by QAxBase in its method internalProperty to convert QVariants to the Microsoft VARIANT format when setting properties.


case QVariant::LongLong:
// arg.vt is set by QAxBase to VT_ERROR and out == false, so the first two if-cases are skipped
if (out && arg.vt == (VT_CY|VT_BYREF)) {
arg.pcyVal->int64 = qvar.toLongLong();
// this checks for VisualStudio 2005 or higher
#if !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
} else if (out && arg.vt == (VT_I8|VT_BYREF)) {
*arg.pllVal = qvar.toLongLong();
} else {
arg.vt = VT_I8; // method jumps here because I use VisualStudio 2010 on Win7Pro
arg.llVal = qvar.toLongLong(); // here it sets an integer value, not a currency value
if (out) {
arg.pllVal = new LONGLONG(arg.llVal);
arg.vt |= VT_BYREF;
}
}
#else
} else {
arg.vt = VT_CY; // if it jumped here everything would be fine.
arg.cyVal.int64 = qvar.toLongLong();
if (out) {
arg.pcyVal = new CY(arg.cyVal);
arg.vt |= VT_BYREF;
}
}
#endif
break;

Why does it check for _MSC_VER >= 1400 (Visual Studio 2005)? If I used something older or no VisualStudio at all, then there wouldn't be a problem. This basically removes support for the Currency type from VisualStudio/Qt.

ChrisW67
27th July 2012, 01:44
This might seem familiar: https://bugreports.qt-project.org/browse/QTBUG-3828

Why do you think arg.vt == VT_ERROR? That seems an odd thing.

drfitz
27th July 2012, 10:02
Thanks for the link. We were about to write a Qt bug report. Good to know it's been hanging around there since 2009. :) Well, we'll probably have write our own fix if they don't.

Why do you think arg.vt == VT_ERROR? That seems an odd thing.
It's just an initial value. This is what QAxBase does when it calls the method:

int QAxBase::internalProperty(QMetaObject::Call call, int index, void **v)
{
....
case QMetaObject::WriteProperty:
{
.....
arg.vt = VT_ERROR;
.....
QVariantToVARIANT(qvar, arg, proptype);
if (arg.vt == VT_EMPTY || arg.vt == VT_ERROR) {
qWarning("QAxBase::setProperty: Unhandled property type %s", prop.typeName());
break;
}