| /**************************************************************************** |
| ** |
| ** Copyright (C) 2015 The Qt Company Ltd. |
| ** Contact: http://www.qt.io/licensing/ |
| ** |
| ** This file is part of the ActiveQt framework of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:BSD$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** BSD License Usage |
| ** Alternatively, you may use this file under the terms of the BSD license |
| ** as follows: |
| ** |
| ** "Redistribution and use in source and binary forms, with or without |
| ** modification, are permitted provided that the following conditions are |
| ** met: |
| ** * Redistributions of source code must retain the above copyright |
| ** notice, this list of conditions and the following disclaimer. |
| ** * Redistributions in binary form must reproduce the above copyright |
| ** notice, this list of conditions and the following disclaimer in |
| ** the documentation and/or other materials provided with the |
| ** distribution. |
| ** * Neither the name of The Qt Company Ltd nor the names of its |
| ** contributors may be used to endorse or promote products derived |
| ** from this software without specific prior written permission. |
| ** |
| ** |
| ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #define NOMINMAX |
| |
| #include <ocidl.h> |
| #include <olectl.h> |
| |
| #include "qaxtypes.h" |
| #include "qaxutils_p.h" |
| |
| #include <qcursor.h> |
| #include <qpixmap.h> |
| #include <qpainter.h> |
| #include <qobject.h> |
| #include <qdebug.h> |
| #ifdef QAX_SERVER |
| # include <qaxfactory.h> |
| # include <private/qsystemlibrary_p.h> |
| #else |
| # include <quuid.h> |
| # include <qaxobject.h> |
| #endif |
| |
| QT_BEGIN_NAMESPACE |
| |
| #ifdef QAX_SERVER |
| # define QVariantToVARIANT QVariantToVARIANT_server |
| # define VARIANTToQVariant VARIANTToQVariant_server |
| extern ITypeLib *qAxTypeLibrary; |
| |
| CLSID CLSID_QRect = { 0x34030f30, 0xe359, 0x4fe6, {0xab, 0x82, 0x39, 0x76, 0x6f, 0x5d, 0x91, 0xee } }; |
| CLSID CLSID_QSize = { 0xcb5f84b3, 0x29e5, 0x491d, {0xba, 0x18, 0x54, 0x72, 0x48, 0x8e, 0xef, 0xba } }; |
| CLSID CLSID_QPoint = { 0x3be838a3, 0x3fac, 0xbfc4, {0x4c, 0x6c, 0x37, 0xc4, 0x4d, 0x03, 0x02, 0x52 } }; |
| |
| GUID IID_IAxServerBase = { 0xbd2ec165, 0xdfc9, 0x4319, { 0x8b, 0x9b, 0x60, 0xa5, 0x74, 0x78, 0xe9, 0xe3} }; |
| #else |
| # define QVariantToVARIANT QVariantToVARIANT_container |
| # define VARIANTToQVariant VARIANTToQVariant_container |
| extern void *qax_createObjectWrapper(int metaType, IUnknown *iface); |
| #endif |
| |
| static IFontDisp *QFontToIFont(const QFont &font) |
| { |
| FONTDESC fdesc; |
| memset(&fdesc, 0, sizeof(fdesc)); |
| fdesc.cbSizeofstruct = sizeof(FONTDESC); |
| fdesc.cySize.Lo = font.pointSize() * 10000; |
| fdesc.fItalic = font.italic(); |
| fdesc.fStrikethrough = font.strikeOut(); |
| fdesc.fUnderline = font.underline(); |
| fdesc.lpstrName = QStringToBSTR(font.family()); |
| fdesc.sWeight = font.weight() * 10; |
| |
| IFontDisp *f; |
| HRESULT res = OleCreateFontIndirect(&fdesc, IID_IFontDisp, reinterpret_cast<void**>(&f)); |
| if (res != S_OK) { |
| if (f) f->Release(); |
| f = nullptr; |
| #if defined(QT_CHECK_STATE) |
| qWarning("QFontToIFont: Failed to create IFont"); |
| #endif |
| } |
| return f; |
| } |
| |
| static QFont IFontToQFont(IFont *f) |
| { |
| BSTR name; |
| BOOL bold; |
| SHORT charset; |
| BOOL italic; |
| CY size; |
| BOOL strike; |
| BOOL underline; |
| SHORT weight; |
| f->get_Name(&name); |
| f->get_Bold(&bold); |
| f->get_Charset(&charset); |
| f->get_Italic(&italic); |
| f->get_Size(&size); |
| f->get_Strikethrough(&strike); |
| f->get_Underline(&underline); |
| f->get_Weight(&weight); |
| QFont font(QString::fromWCharArray(name), size.Lo/9750, weight / 97, italic); |
| font.setBold(bold); |
| font.setStrikeOut(strike); |
| font.setUnderline(underline); |
| SysFreeString(name); |
| |
| return font; |
| } |
| |
| Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0); |
| Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0); |
| |
| static IPictureDisp *QPixmapToIPicture(const QPixmap &pixmap) |
| { |
| IPictureDisp *pic = nullptr; |
| |
| PICTDESC desc; |
| desc.cbSizeofstruct = sizeof(PICTDESC); |
| desc.picType = PICTYPE_BITMAP; |
| |
| desc.bmp.hbitmap = nullptr; |
| desc.bmp.hpal = nullptr; |
| |
| if (!pixmap.isNull()) { |
| desc.bmp.hbitmap = qt_pixmapToWinHBITMAP(pixmap); |
| Q_ASSERT(desc.bmp.hbitmap); |
| } |
| |
| HRESULT res = OleCreatePictureIndirect(&desc, IID_IPictureDisp, true, reinterpret_cast<void**>(&pic)); |
| if (res != S_OK) { |
| if (pic) pic->Release(); |
| pic = nullptr; |
| #if defined(QT_CHECK_STATE) |
| qWarning("QPixmapToIPicture: Failed to create IPicture"); |
| #endif |
| } |
| return pic; |
| } |
| |
| static QPixmap IPictureToQPixmap(IPicture *ipic) |
| { |
| SHORT type; |
| ipic->get_Type(&type); |
| if (type != PICTYPE_BITMAP) |
| return QPixmap(); |
| |
| HBITMAP hbm = nullptr; |
| ipic->get_Handle(reinterpret_cast<OLE_HANDLE*>(&hbm)); |
| if (!hbm) |
| return QPixmap(); |
| |
| return qt_pixmapFromWinHBITMAP(hbm); |
| } |
| |
| static QDateTime DATEToQDateTime(DATE ole) |
| { |
| SYSTEMTIME stime; |
| if (ole >= 949998 || !VariantTimeToSystemTime(ole, &stime)) |
| return QDateTime(); |
| |
| QDate date(stime.wYear, stime.wMonth, stime.wDay); |
| QTime time(stime.wHour, stime.wMinute, stime.wSecond, stime.wMilliseconds); |
| return QDateTime(date, time); |
| } |
| |
| static DATE QDateTimeToDATE(const QDateTime &dt) |
| { |
| if (!dt.isValid() || dt.isNull()) |
| return 949998; |
| |
| SYSTEMTIME stime; |
| memset(&stime, 0, sizeof(stime)); |
| QDate date = dt.date(); |
| QTime time = dt.time(); |
| if (date.isValid() && !date.isNull()) { |
| stime.wDay = date.day(); |
| stime.wMonth = date.month(); |
| stime.wYear = date.year(); |
| } |
| if (time.isValid() && !time.isNull()) { |
| stime.wMilliseconds = time.msec(); |
| stime.wSecond = time.second(); |
| stime.wMinute = time.minute(); |
| stime.wHour = time.hour(); |
| } |
| |
| double vtime; |
| SystemTimeToVariantTime(&stime, &vtime); |
| |
| return vtime; |
| } |
| |
| static QByteArray msgOutParameterNotSupported(const QByteArray &type) |
| { |
| return QByteArrayLiteral("QVariantToVARIANT: out-parameter not supported for \"") |
| + type + QByteArrayLiteral("\"."); |
| } |
| |
| /* |
| Converts \a var to \a arg, and tries to coerce \a arg to \a type. |
| |
| Used by |
| |
| QAxServerBase: |
| - QAxServerBase::qt_metacall |
| - IDispatch::Invoke(PROPERTYGET, METHOD) |
| - IPersistPropertyBag::Save |
| |
| QAxBase: |
| - IDispatch::Invoke (QAxEventSink) |
| - QAxBase::internalProperty(WriteProperty) |
| - QAxBase::internalInvoke() |
| - QAxBase::dynamicCallHelper() |
| - IPropertyBag::Read (QtPropertyBag) |
| |
| Also called recoursively for lists. |
| */ |
| |
| // Convenience macro for function QVariantToVARIANT() |
| // storing a POD QVariant value in the VARIANT arg. |
| #define QVARIANT_TO_VARIANT_POD(type, value, out, varType, varMember, varPointerMember) \ |
| if (out && arg.vt == ((varType) | VT_BYREF)) { \ |
| *arg.varPointerMember = value; /* pre-allocated out-parameter */ \ |
| } else { \ |
| if (out) { \ |
| arg.vt = (varType) | VT_BYREF; \ |
| arg.varPointerMember = new type(value); \ |
| } else { \ |
| arg.vt = (varType); \ |
| arg.varMember = value; \ |
| } \ |
| } |
| |
| bool QVariantToVARIANT(const QVariant &var, VARIANT &arg, const QByteArray &typeName, bool out) |
| { |
| QVariant qvar = var; |
| // "type" is the expected type, so coerce if necessary |
| const QVariant::Type proptype = typeName.isEmpty() ? QVariant::Invalid : QVariant::nameToType(typeName); |
| if (proptype != QVariant::Invalid |
| && proptype != QVariant::UserType |
| && proptype != int(QMetaType::QVariant) |
| && proptype != qvar.type()) { |
| if (qvar.canConvert(proptype)) |
| qvar.convert(proptype); |
| else |
| qvar = QVariant(proptype); |
| } |
| |
| if (out && arg.vt == (VT_VARIANT|VT_BYREF) && arg.pvarVal) { |
| return QVariantToVARIANT(var, *arg.pvarVal, typeName, false); |
| } |
| |
| if (out && proptype == QVariant::UserType && typeName == "QVariant") { |
| VARIANT *pVariant = new VARIANT; |
| QVariantToVARIANT(var, *pVariant, QByteArray(), false); |
| arg.vt = VT_VARIANT|VT_BYREF; |
| arg.pvarVal = pVariant; |
| return true; |
| } |
| |
| switch ((int)qvar.type()) { |
| case QVariant::String: |
| if (out && arg.vt == (VT_BSTR|VT_BYREF)) { |
| if (*arg.pbstrVal) |
| SysFreeString(*arg.pbstrVal); |
| *arg.pbstrVal = QStringToBSTR(qvar.toString()); |
| arg.vt = VT_BSTR|VT_BYREF; |
| } else { |
| arg.vt = VT_BSTR; |
| arg.bstrVal = QStringToBSTR(qvar.toString()); |
| if (out) { |
| arg.pbstrVal = new BSTR(arg.bstrVal); |
| arg.vt |= VT_BYREF; |
| } |
| } |
| break; |
| |
| case QMetaType::Char: |
| QVARIANT_TO_VARIANT_POD(char, char(qvar.toInt()), out, VT_I1, cVal, pcVal) |
| break; |
| |
| case QMetaType::UChar: |
| QVARIANT_TO_VARIANT_POD(BYTE, uchar(qvar.toUInt()), out, VT_UI1, bVal, pbVal) |
| break; |
| |
| case QMetaType::Short: |
| QVARIANT_TO_VARIANT_POD(short, qvariant_cast<short>(qvar), out, VT_I2, iVal, piVal) |
| break; |
| |
| case QMetaType::UShort: |
| QVARIANT_TO_VARIANT_POD(ushort, qvariant_cast<ushort>(qvar), out, VT_UI2, uiVal, puiVal) |
| break; |
| |
| case QVariant::Int: |
| QVARIANT_TO_VARIANT_POD(long, qvar.toInt(), out, VT_I4, lVal, plVal) |
| break; |
| |
| case QVariant::UInt: |
| QVARIANT_TO_VARIANT_POD(uint, qvar.toUInt(), out, VT_UI4, uintVal, puintVal) |
| break; |
| |
| case QVariant::LongLong: |
| if (out && arg.vt == (VT_CY|VT_BYREF)) { // VT_CY: Currency |
| arg.pcyVal->int64 = qvar.toLongLong(); |
| } else { |
| QVARIANT_TO_VARIANT_POD(LONGLONG, qvar.toLongLong(), out, VT_I8, llVal, pllVal) |
| } |
| break; |
| |
| case QVariant::ULongLong: |
| if (out && arg.vt == (VT_CY|VT_BYREF)) { // VT_CY: Currency |
| arg.pcyVal->int64 = qvar.toULongLong(); |
| } else { |
| QVARIANT_TO_VARIANT_POD(ULONGLONG, qvar.toULongLong(), out, VT_UI8, ullVal, pullVal) |
| } |
| break; |
| |
| case QVariant::Bool: |
| QVARIANT_TO_VARIANT_POD(short, short(qvar.toBool() ? VARIANT_TRUE : VARIANT_FALSE), |
| out, VT_BOOL, boolVal, pboolVal) |
| break; |
| |
| case QMetaType::Float: |
| QVARIANT_TO_VARIANT_POD(float, float(qvar.toDouble()), out, VT_R4, fltVal, pfltVal) |
| break; |
| |
| case QMetaType::Double: |
| QVARIANT_TO_VARIANT_POD(double, qvar.toDouble(), out, VT_R8, dblVal, pdblVal) |
| break; |
| |
| case QVariant::Color: |
| QVARIANT_TO_VARIANT_POD(long, QColorToOLEColor(qvariant_cast<QColor>(qvar)), |
| out, VT_COLOR, lVal, plVal) |
| break; |
| |
| case QVariant::Date: |
| case QVariant::Time: |
| case QVariant::DateTime: // DATE = double |
| QVARIANT_TO_VARIANT_POD(DATE, QDateTimeToDATE(qvar.toDateTime()), |
| out, VT_DATE, date, pdate) |
| break; |
| |
| case QVariant::Font: |
| if (out && arg.vt == (VT_DISPATCH|VT_BYREF)) { |
| if (*arg.ppdispVal) |
| (*arg.ppdispVal)->Release(); |
| *arg.ppdispVal = QFontToIFont(qvariant_cast<QFont>(qvar)); |
| } else { |
| arg.vt = VT_DISPATCH; |
| arg.pdispVal = QFontToIFont(qvariant_cast<QFont>(qvar)); |
| if (out) { |
| arg.ppdispVal = new IDispatch*(arg.pdispVal); |
| arg.vt |= VT_BYREF; |
| } |
| } |
| break; |
| |
| case QVariant::Pixmap: |
| if (out && arg.vt == (VT_DISPATCH|VT_BYREF)) { |
| if (*arg.ppdispVal) |
| (*arg.ppdispVal)->Release(); |
| *arg.ppdispVal = QPixmapToIPicture(qvariant_cast<QPixmap>(qvar)); |
| } else { |
| arg.vt = VT_DISPATCH; |
| arg.pdispVal = QPixmapToIPicture(qvariant_cast<QPixmap>(qvar)); |
| if (out) { |
| arg.ppdispVal = new IDispatch*(arg.pdispVal); |
| arg.vt |= VT_BYREF; |
| } |
| } |
| break; |
| |
| case QVariant::Cursor: |
| { |
| #ifndef QT_NO_CURSOR |
| int shape = qvariant_cast<QCursor>(qvar).shape(); |
| if (out && (arg.vt & VT_BYREF)) { |
| switch(arg.vt & ~VT_BYREF) { |
| case VT_I4: |
| *arg.plVal = shape; |
| break; |
| case VT_I2: |
| *arg.piVal = shape; |
| break; |
| case VT_UI4: |
| *arg.pulVal = shape; |
| break; |
| case VT_UI2: |
| *arg.puiVal = shape; |
| break; |
| case VT_INT: |
| *arg.pintVal = shape; |
| break; |
| case VT_UINT: |
| *arg.puintVal = shape; |
| break; |
| } |
| } else { |
| arg.vt = VT_I4; |
| arg.lVal = shape; |
| if (out) { |
| arg.plVal = new long(arg.lVal); |
| arg.vt |= VT_BYREF; |
| } |
| } |
| #endif |
| } |
| break; |
| |
| case QVariant::List: |
| { |
| const QList<QVariant> list = qvar.toList(); |
| const int count = list.count(); |
| VARTYPE vt = VT_VARIANT; |
| QVariant::Type listType = QVariant::Type(QMetaType::QVariant); |
| if (!typeName.isEmpty() && typeName.startsWith("QList<")) { |
| const QByteArray listTypeName = typeName.mid(6, typeName.length() - 7); // QList<int> -> int |
| listType = QVariant::nameToType(listTypeName); |
| } |
| |
| VARIANT variant; |
| void *pElement = &variant; |
| switch(listType) { |
| case QVariant::Int: |
| vt = VT_I4; |
| pElement = &variant.lVal; |
| break; |
| case QVariant::Double: |
| vt = VT_R8; |
| pElement = &variant.dblVal; |
| break; |
| case QVariant::DateTime: |
| vt = VT_DATE; |
| pElement = &variant.date; |
| break; |
| case QVariant::Bool: |
| vt = VT_BOOL; |
| pElement = &variant.boolVal; |
| break; |
| case QVariant::LongLong: |
| vt = VT_I8; |
| pElement = &variant.llVal; |
| break; |
| default: |
| break; |
| } |
| SAFEARRAY *array = nullptr; |
| bool is2D = false; |
| // If the first element in the array is a list the whole list is |
| // treated as a 2D array. The column count is taken from the 1st element. |
| if (count) { |
| QVariantList col = list.at(0).toList(); |
| int maxColumns = col.count(); |
| if (maxColumns) { |
| is2D = true; |
| SAFEARRAYBOUND rgsabound[2] = { {0, 0}, {0, 0} }; |
| rgsabound[0].cElements = count; |
| rgsabound[1].cElements = maxColumns; |
| array = SafeArrayCreate(VT_VARIANT, 2, rgsabound); |
| LONG rgIndices[2]; |
| for (LONG i = 0; i < count; ++i) { |
| rgIndices[0] = i; |
| QVariantList columns = list.at(i).toList(); |
| int columnCount = qMin(maxColumns, columns.count()); |
| for (LONG j = 0; j < columnCount; ++j) { |
| const QVariant &elem = columns.at(j); |
| VariantInit(&variant); |
| QVariantToVARIANT(elem, variant, elem.typeName()); |
| rgIndices[1] = j; |
| SafeArrayPutElement(array, rgIndices, pElement); |
| clearVARIANT(&variant); |
| } |
| } |
| |
| } |
| } |
| if (!is2D) { |
| array = SafeArrayCreateVector(vt, 0, count); |
| for (LONG index = 0; index < count; ++index) { |
| QVariant elem = list.at(index); |
| if (listType != QVariant::Type(QMetaType::QVariant)) |
| elem.convert(listType); |
| VariantInit(&variant); |
| QVariantToVARIANT(elem, variant, elem.typeName()); |
| SafeArrayPutElement(array, &index, pElement); |
| clearVARIANT(&variant); |
| } |
| } |
| if (out && arg.vt == (VT_ARRAY|vt|VT_BYREF)) { |
| if (*arg.pparray) |
| SafeArrayDestroy(*arg.pparray); |
| *arg.pparray = array; |
| } else { |
| arg.vt = VT_ARRAY|vt; |
| arg.parray = array; |
| if (out) { |
| arg.pparray = new SAFEARRAY*(arg.parray); |
| arg.vt |= VT_BYREF; |
| } |
| } |
| } |
| break; |
| |
| case QVariant::StringList: |
| { |
| const QStringList list = qvar.toStringList(); |
| const int count = list.count(); |
| SAFEARRAY *array = SafeArrayCreateVector(VT_BSTR, 0, count); |
| for (LONG index = 0; index < count; ++index) { |
| QString elem = list.at(index); |
| BSTR bstr = QStringToBSTR(elem); |
| SafeArrayPutElement(array, &index, bstr); |
| SysFreeString(bstr); |
| } |
| |
| if (out && arg.vt == (VT_ARRAY|VT_BSTR|VT_BYREF)) { |
| if (*arg.pparray) |
| SafeArrayDestroy(*arg.pparray); |
| *arg.pparray = array; |
| } else { |
| arg.vt = VT_ARRAY|VT_BSTR; |
| arg.parray = array; |
| if (out) { |
| arg.pparray = new SAFEARRAY*(arg.parray); |
| arg.vt |= VT_BYREF; |
| } |
| } |
| } |
| break; |
| |
| case QVariant::ByteArray: |
| { |
| const QByteArray bytes = qvar.toByteArray(); |
| const uint count = bytes.count(); |
| SAFEARRAY *array = SafeArrayCreateVector(VT_UI1, 0, count); |
| if (count) { |
| const char *data = bytes.constData(); |
| char *dest; |
| SafeArrayAccessData(array, reinterpret_cast<void**>(&dest)); |
| memcpy(dest, data, count); |
| SafeArrayUnaccessData(array); |
| } |
| |
| if (out && arg.vt == (VT_ARRAY|VT_UI1|VT_BYREF)) { |
| if (*arg.pparray) |
| SafeArrayDestroy(*arg.pparray); |
| *arg.pparray = array; |
| } else { |
| arg.vt = VT_ARRAY|VT_UI1; |
| arg.parray = array; |
| if (out) { |
| arg.pparray = new SAFEARRAY*(arg.parray); |
| arg.vt |= VT_BYREF; |
| } |
| } |
| } |
| break; |
| |
| #ifdef QAX_SERVER |
| case QVariant::Rect: |
| case QVariant::Size: |
| case QVariant::Point: |
| { |
| typedef HRESULT(WINAPI* PGetRecordInfoFromTypeInfo)(ITypeInfo *, IRecordInfo **); |
| static PGetRecordInfoFromTypeInfo pGetRecordInfoFromTypeInfo = 0; |
| static bool resolved = false; |
| if (!resolved) { |
| resolved = true; |
| pGetRecordInfoFromTypeInfo = (PGetRecordInfoFromTypeInfo)QSystemLibrary::resolve(QLatin1String("oleaut32"), |
| "GetRecordInfoFromTypeInfo"); |
| } |
| if (!pGetRecordInfoFromTypeInfo) |
| break; |
| |
| ITypeInfo *typeInfo = 0; |
| IRecordInfo *recordInfo = 0; |
| CLSID clsid = qvar.type() == QVariant::Rect ? CLSID_QRect |
| :qvar.type() == QVariant::Size ? CLSID_QSize |
| :CLSID_QPoint; |
| qAxTypeLibrary->GetTypeInfoOfGuid(clsid, &typeInfo); |
| if (!typeInfo) |
| break; |
| pGetRecordInfoFromTypeInfo(typeInfo, &recordInfo); |
| typeInfo->Release(); |
| if (!recordInfo) |
| break; |
| |
| void *record = 0; |
| switch (qvar.type()) { |
| case QVariant::Rect: |
| { |
| QRect qrect(qvar.toRect()); |
| recordInfo->RecordCreateCopy(&qrect, &record); |
| } |
| break; |
| case QVariant::Size: |
| { |
| QSize qsize(qvar.toSize()); |
| recordInfo->RecordCreateCopy(&qsize, &record); |
| } |
| break; |
| case QVariant::Point: |
| { |
| QPoint qpoint(qvar.toPoint()); |
| recordInfo->RecordCreateCopy(&qpoint, &record); |
| } |
| break; |
| default: |
| break; |
| } |
| |
| if (out) { |
| qWarning().noquote() << msgOutParameterNotSupported("records"); |
| arg.vt = VT_EMPTY; |
| arg.byref = nullptr; |
| return false; |
| } |
| arg.vt = VT_RECORD; |
| arg.pRecInfo = recordInfo, |
| arg.pvRecord = record; |
| } |
| break; |
| #endif // QAX_SERVER |
| case QVariant::UserType: |
| { |
| QByteArray subType = qvar.typeName(); |
| #ifdef QAX_SERVER |
| if (subType.endsWith('*')) |
| subType.truncate(subType.length() - 1); |
| #endif |
| if (!qstrcmp(qvar.typeName(), "IDispatch*")) { |
| if (out) { |
| qWarning().noquote() << msgOutParameterNotSupported(qvar.typeName()); |
| arg.vt = VT_EMPTY; |
| arg.byref = nullptr; |
| return false; |
| } |
| arg.vt = VT_DISPATCH; |
| arg.pdispVal = *static_cast<IDispatch**>(qvar.data()); |
| if (arg.pdispVal) |
| arg.pdispVal->AddRef(); |
| } else if (!qstrcmp(qvar.typeName(), "IDispatch**")) { |
| arg.vt = VT_DISPATCH; |
| arg.ppdispVal = *static_cast<IDispatch***>(qvar.data()); |
| if (out) |
| arg.vt |= VT_BYREF; |
| } else if (!qstrcmp(qvar.typeName(), "IUnknown*")) { |
| if (out) { |
| qWarning().noquote() << msgOutParameterNotSupported(qvar.typeName()); |
| arg.vt = VT_EMPTY; |
| arg.byref = nullptr; |
| return false; |
| } |
| arg.vt = VT_UNKNOWN; |
| arg.punkVal = *static_cast<IUnknown**>(qvar.data()); |
| if (arg.punkVal) |
| arg.punkVal->AddRef(); |
| #ifdef QAX_SERVER |
| } else if (qAxFactory()->metaObject(QString::fromLatin1(subType.constData()))) { |
| if (out) { |
| qWarning().noquote() << msgOutParameterNotSupported("subtype"); |
| arg.vt = VT_EMPTY; |
| arg.byref = nullptr; |
| return false; |
| } |
| arg.vt = VT_DISPATCH; |
| void *user = *(void**)qvar.constData(); |
| // qVariantGet(qvar, user, qvar.typeName()); |
| if (!user) { |
| arg.pdispVal = 0; |
| } else { |
| qAxFactory()->createObjectWrapper(static_cast<QObject*>(user), &arg.pdispVal); |
| } |
| #else |
| } else if (QMetaType::type(subType)) { |
| if (out) { |
| qWarning().noquote() << msgOutParameterNotSupported("subtype"); |
| arg.vt = VT_EMPTY; |
| arg.byref = nullptr; |
| return false; |
| } |
| QAxObject *object = *static_cast<QAxObject**>(qvar.data()); |
| // qVariantGet(qvar, object, subType); |
| arg.vt = VT_DISPATCH; |
| object->queryInterface(IID_IDispatch, reinterpret_cast<void**>(&arg.pdispVal)); |
| #endif |
| } else { |
| return false; |
| } |
| } |
| break; |
| case QVariant::Invalid: // default-parameters not set |
| if (out && arg.vt == (VT_ERROR|VT_BYREF)) { |
| *arg.plVal = DISP_E_PARAMNOTFOUND; |
| } else { |
| arg.vt = VT_ERROR; |
| arg.lVal = DISP_E_PARAMNOTFOUND; |
| if (out) { |
| arg.plVal = new long(arg.lVal); |
| arg.vt |= VT_BYREF; |
| } |
| } |
| break; |
| |
| default: |
| return false; |
| } |
| |
| Q_ASSERT(!out || (arg.vt & VT_BYREF)); |
| return true; |
| } |
| |
| #undef QVARIANT_TO_VARIANT_POD |
| |
| /* |
| Returns \a arg as a QVariant of type \a type. |
| |
| Used by |
| |
| QAxServerBase: |
| - QAxServerBase::qt_metacall(update out parameters/return value) |
| - IDispatch::Invoke(METHOD, PROPERTYPUT) |
| - IPersistPropertyBag::Load |
| |
| QAxBase: |
| - IDispatch::Invoke (QAxEventSink) |
| - QAxBase::internalProperty(ReadProperty) |
| - QAxBase::internalInvoke(update out parameters/return value) |
| - QAxBase::dynamicCallHelper(update out parameters) |
| - QAxBase::dynamicCall(return value) |
| - IPropertyBag::Write (QtPropertyBag) |
| */ |
| QVariant VARIANTToQVariant(const VARIANT &arg, const QByteArray &typeName, uint type) |
| { |
| QVariant var; |
| switch(arg.vt) { |
| case VT_BSTR: |
| var = QString::fromWCharArray(arg.bstrVal); |
| break; |
| case VT_BSTR|VT_BYREF: |
| var = QString::fromWCharArray(*arg.pbstrVal); |
| break; |
| case VT_BOOL: |
| var = QVariant((bool)arg.boolVal); |
| break; |
| case VT_BOOL|VT_BYREF: |
| var = QVariant((bool)*arg.pboolVal); |
| break; |
| case VT_I1: |
| var = arg.cVal; |
| if (typeName == "char") |
| type = QVariant::Int; |
| break; |
| case VT_I1|VT_BYREF: |
| var = *arg.pcVal; |
| if (typeName == "char") |
| type = QVariant::Int; |
| break; |
| case VT_I2: |
| var = arg.iVal; |
| if (typeName == "short") |
| type = QVariant::Int; |
| break; |
| case VT_I2|VT_BYREF: |
| var = *arg.piVal; |
| if (typeName == "short") |
| type = QVariant::Int; |
| break; |
| case VT_I4: |
| if (type == QVariant::Color || (!type && typeName == "QColor")) |
| var = QVariant::fromValue(OLEColorToQColor(arg.lVal)); |
| #ifndef QT_NO_CURSOR |
| else if (type == QVariant::Cursor || (!type && (typeName == "QCursor" || typeName == "QCursor*"))) |
| var = QVariant::fromValue(QCursor(static_cast<Qt::CursorShape>(arg.lVal))); |
| #endif |
| else |
| var = (int)arg.lVal; |
| break; |
| case VT_I4|VT_BYREF: |
| if (type == QVariant::Color || (!type && typeName == "QColor")) |
| var = QVariant::fromValue(OLEColorToQColor((int)*arg.plVal)); |
| #ifndef QT_NO_CURSOR |
| else if (type == QVariant::Cursor || (!type && (typeName == "QCursor" || typeName == "QCursor*"))) |
| var = QVariant::fromValue(QCursor(static_cast<Qt::CursorShape>(*arg.plVal))); |
| #endif |
| else |
| var = (int)*arg.plVal; |
| break; |
| case VT_INT: |
| var = arg.intVal; |
| break; |
| case VT_INT|VT_BYREF: |
| var = *arg.pintVal; |
| break; |
| case VT_UI1: |
| var = arg.bVal; |
| break; |
| case VT_UI1|VT_BYREF: |
| var = *arg.pbVal; |
| break; |
| case VT_UI2: |
| var = arg.uiVal; |
| break; |
| case VT_UI2|VT_BYREF: |
| var = *arg.puiVal; |
| break; |
| case VT_UI4: |
| if (type == QVariant::Color || (!type && typeName == "QColor")) |
| var = QVariant::fromValue(OLEColorToQColor(arg.ulVal)); |
| #ifndef QT_NO_CURSOR |
| else if (type == QVariant::Cursor || (!type && (typeName == "QCursor" || typeName == "QCursor*"))) |
| var = QVariant::fromValue(QCursor(static_cast<Qt::CursorShape>(arg.ulVal))); |
| #endif |
| else |
| var = (int)arg.ulVal; |
| break; |
| case VT_UI4|VT_BYREF: |
| if (type == QVariant::Color || (!type && typeName == "QColor")) |
| var = QVariant::fromValue(OLEColorToQColor((uint)*arg.pulVal)); |
| #ifndef QT_NO_CURSOR |
| else if (type == QVariant::Cursor || (!type && (typeName == "QCursor" || typeName == "QCursor*"))) |
| var = QVariant::fromValue(QCursor(static_cast<Qt::CursorShape>(*arg.pulVal))); |
| #endif |
| else |
| var = (int)*arg.pulVal; |
| break; |
| case VT_UINT: |
| var = arg.uintVal; |
| break; |
| case VT_UINT|VT_BYREF: |
| var = *arg.puintVal; |
| break; |
| case VT_CY: |
| var = arg.cyVal.int64; |
| break; |
| case VT_CY|VT_BYREF: |
| var = arg.pcyVal->int64; |
| break; |
| case VT_I8: |
| var = arg.llVal; |
| break; |
| case VT_I8|VT_BYREF: |
| var = *arg.pllVal; |
| break; |
| case VT_UI8: |
| var = arg.ullVal; |
| break; |
| case VT_UI8|VT_BYREF: |
| var = *arg.pullVal; |
| break; |
| case VT_R4: |
| var = arg.fltVal; |
| break; |
| case VT_R4|VT_BYREF: |
| var = *arg.pfltVal; |
| break; |
| case VT_R8: |
| var = arg.dblVal; |
| break; |
| case VT_R8|VT_BYREF: |
| var = *arg.pdblVal; |
| break; |
| case VT_DATE: |
| var = DATEToQDateTime(arg.date); |
| if (type == QVariant::Date || (!type && (typeName == "QDate" || typeName == "QDate*"))) { |
| var.convert(QVariant::Date); |
| } else if (type == QVariant::Time || (!type && (typeName == "QTime" || typeName == "QTime*"))) { |
| var.convert(QVariant::Time); |
| } |
| break; |
| case VT_DATE|VT_BYREF: |
| var = DATEToQDateTime(*arg.pdate); |
| if (type == QVariant::Date || (!type && (typeName == "QDate" || typeName == "QDate*"))) { |
| var.convert(QVariant::Date); |
| } else if (type == QVariant::Time || (!type && (typeName == "QTime" || typeName == "QTime*"))) { |
| var.convert(QVariant::Time); |
| } |
| break; |
| case VT_VARIANT: |
| case VT_VARIANT|VT_BYREF: |
| if (arg.pvarVal) |
| var = VARIANTToQVariant(*arg.pvarVal, typeName); |
| break; |
| |
| case VT_DISPATCH: |
| case VT_DISPATCH|VT_BYREF: |
| { |
| // pdispVal and ppdispVal are a union |
| IDispatch *disp = nullptr; |
| if (arg.vt & VT_BYREF) |
| disp = *arg.ppdispVal; |
| else |
| disp = arg.pdispVal; |
| if (type == QVariant::Font || (!type && (typeName == "QFont" || typeName == "QFont*"))) { |
| IFont *ifont = nullptr; |
| if (disp) |
| disp->QueryInterface(IID_IFont, reinterpret_cast<void**>(&ifont)); |
| if (ifont) { |
| var = QVariant::fromValue(IFontToQFont(ifont)); |
| ifont->Release(); |
| } else { |
| var = QVariant::fromValue(QFont()); |
| } |
| } else if (type == QVariant::Pixmap || (!type && (typeName == "QPixmap" || typeName == "QPixmap*"))) { |
| IPicture *ipic = nullptr; |
| if (disp) |
| disp->QueryInterface(IID_IPicture, reinterpret_cast<void**>(&ipic)); |
| if (ipic) { |
| var = QVariant::fromValue(IPictureToQPixmap(ipic)); |
| ipic->Release(); |
| } else { |
| var = QVariant::fromValue(QPixmap()); |
| } |
| } else { |
| #ifdef QAX_SERVER |
| IAxServerBase *iface = 0; |
| if (disp && typeName != "IDispatch*") |
| disp->QueryInterface(IID_IAxServerBase, reinterpret_cast<void**>(&iface)); |
| if (iface) { |
| QObject *qObj = iface->qObject(); |
| iface->Release(); |
| QByteArray pointerType = qObj ? QByteArray(qObj->metaObject()->className()) + '*' : typeName; |
| int pointerTypeId = QMetaType::type(pointerType); |
| if (!pointerTypeId) |
| pointerTypeId = qRegisterMetaType<QObject *>(pointerType); |
| var = QVariant(pointerTypeId, &qObj); |
| } else |
| #endif |
| { |
| if (!typeName.isEmpty()) { |
| if (arg.vt & VT_BYREF) { |
| var = QVariant(qRegisterMetaType<IDispatch**>("IDispatch**"), &arg.ppdispVal); |
| } else { |
| #ifndef QAX_SERVER |
| if (typeName == "QVariant") { |
| QAxObject *object = new QAxObject(disp); |
| var = QVariant::fromValue<QAxObject*>(object); |
| } else if (typeName != "IDispatch*" && QMetaType::type(typeName)) { |
| QByteArray typeNameStr = QByteArray(typeName); |
| int pIndex = typeName.lastIndexOf('*'); |
| if (pIndex != -1) |
| typeNameStr = typeName.left(pIndex); |
| int metaType = QMetaType::type(typeNameStr); |
| Q_ASSERT(metaType != 0); |
| auto object = static_cast<QAxObject*>(qax_createObjectWrapper(metaType, disp)); |
| var = QVariant(QMetaType::type(typeName), &object); |
| } else |
| #endif |
| var = QVariant(qRegisterMetaType<IDispatch*>(typeName), &disp); |
| } |
| } |
| } |
| } |
| } |
| break; |
| case VT_UNKNOWN: |
| case VT_UNKNOWN|VT_BYREF: |
| { |
| IUnknown *unkn = nullptr; |
| if (arg.vt & VT_BYREF) |
| unkn = *arg.ppunkVal; |
| else |
| unkn = arg.punkVal; |
| var.setValue(unkn); |
| } |
| break; |
| case VT_ARRAY|VT_VARIANT: |
| case VT_ARRAY|VT_VARIANT|VT_BYREF: |
| { |
| SAFEARRAY *array = nullptr; |
| if ( arg.vt & VT_BYREF ) |
| array = *arg.pparray; |
| else |
| array = arg.parray; |
| |
| UINT cDims = array ? SafeArrayGetDim(array) : 0; |
| switch(cDims) { |
| case 1: |
| { |
| QVariantList list; |
| |
| long lBound, uBound; |
| SafeArrayGetLBound( array, 1, &lBound ); |
| SafeArrayGetUBound( array, 1, &uBound ); |
| |
| for ( long i = lBound; i <= uBound; ++i ) { |
| VARIANT var; |
| VariantInit( &var ); |
| SafeArrayGetElement( array, &i, &var ); |
| |
| QVariant qvar = VARIANTToQVariant( var, nullptr ); |
| clearVARIANT( &var ); |
| list << qvar; |
| } |
| |
| var = list; |
| } |
| break; |
| |
| case 2: |
| { |
| QVariantList listList; // a list of lists |
| long dimIndices[2]; |
| |
| long xlBound, xuBound, ylBound, yuBound; |
| SafeArrayGetLBound(array, 1, &xlBound); |
| SafeArrayGetUBound(array, 1, &xuBound); |
| SafeArrayGetLBound(array, 2, &ylBound); |
| SafeArrayGetUBound(array, 2, &yuBound); |
| |
| for (long x = xlBound; x <= xuBound; ++x) { |
| QVariantList list; |
| |
| dimIndices[0] = x; |
| for (long y = ylBound; y <= yuBound; ++y) { |
| VARIANT var; |
| VariantInit(&var); |
| dimIndices[1] = y; |
| SafeArrayGetElement(array, dimIndices, &var); |
| |
| QVariant qvar = VARIANTToQVariant(var, nullptr); |
| clearVARIANT(&var); |
| list << qvar; |
| } |
| |
| listList << QVariant(list); |
| } |
| var = listList; |
| } |
| break; |
| default: |
| var = QVariantList(); |
| break; |
| } |
| } |
| break; |
| |
| case VT_ARRAY|VT_BSTR: |
| case VT_ARRAY|VT_BSTR|VT_BYREF: |
| { |
| SAFEARRAY *array = nullptr; |
| if (arg.vt & VT_BYREF) |
| array = *arg.pparray; |
| else |
| array = arg.parray; |
| |
| QStringList strings; |
| if (!array || array->cDims != 1) { |
| var = strings; |
| break; |
| } |
| |
| long lBound, uBound; |
| SafeArrayGetLBound(array, 1, &lBound); |
| SafeArrayGetUBound(array, 1, &uBound); |
| |
| for (long i = lBound; i <= uBound; ++i) { |
| BSTR bstr; |
| SafeArrayGetElement(array, &i, &bstr); |
| strings << QString::fromWCharArray(bstr); |
| SysFreeString(bstr); |
| } |
| |
| var = strings; |
| } |
| break; |
| |
| case VT_ARRAY|VT_UI1: |
| case VT_ARRAY|VT_UI1|VT_BYREF: |
| { |
| SAFEARRAY *array = nullptr; |
| if (arg.vt & VT_BYREF) |
| array = *arg.pparray; |
| else |
| array = arg.parray; |
| |
| QByteArray bytes; |
| if (!array || array->cDims != 1) { |
| var = bytes; |
| break; |
| } |
| |
| long lBound, uBound; |
| SafeArrayGetLBound(array, 1, &lBound); |
| SafeArrayGetUBound(array, 1, &uBound); |
| |
| if (uBound != -1) { // non-empty array |
| bytes.resize(uBound - lBound + 1); |
| char *data = bytes.data(); |
| char *src; |
| SafeArrayAccessData(array, reinterpret_cast<void**>(&src)); |
| memcpy(data, src, bytes.size()); |
| SafeArrayUnaccessData(array); |
| } |
| |
| var = bytes; |
| } |
| break; |
| |
| #if defined(QAX_SERVER) |
| case VT_RECORD: |
| case VT_RECORD|VT_BYREF: |
| if (arg.pvRecord && arg.pRecInfo) { |
| IRecordInfo *recordInfo = arg.pRecInfo; |
| void *record = arg.pvRecord; |
| GUID guid; |
| recordInfo->GetGuid(&guid); |
| |
| if (guid == CLSID_QRect) { |
| QRect qrect; |
| recordInfo->RecordCopy(record, &qrect); |
| var = qrect; |
| } else if (guid == CLSID_QSize) { |
| QSize qsize; |
| recordInfo->RecordCopy(record, &qsize); |
| var = qsize; |
| } else if (guid == CLSID_QPoint) { |
| QPoint qpoint; |
| recordInfo->RecordCopy(record, &qpoint); |
| var = qpoint; |
| } |
| } |
| break; |
| #endif // QAX_SERVER |
| default: |
| // support for any SAFEARRAY(Type) where Type can be converted to a QVariant |
| // -> QVariantList |
| if (arg.vt & VT_ARRAY) { |
| SAFEARRAY *array = nullptr; |
| if (arg.vt & VT_BYREF) |
| array = *arg.pparray; |
| else |
| array = arg.parray; |
| |
| QVariantList list; |
| if (!array || array->cDims != 1) { |
| var = list; |
| break; |
| } |
| |
| // find out where to store the element |
| VARTYPE vt; |
| VARIANT variant; |
| SafeArrayGetVartype(array, &vt); |
| |
| void *pElement = nullptr; |
| switch(vt) { |
| case VT_BSTR: Q_ASSERT(false); break; // already covered |
| case VT_BOOL: pElement = &variant.boolVal; break; |
| case VT_I1: pElement = &variant.cVal; break; |
| case VT_I2: pElement = &variant.iVal; break; |
| case VT_I4: pElement = &variant.lVal; break; |
| case VT_I8: pElement = &variant.llVal; break; |
| case VT_UI8: pElement = &variant.ullVal; break; |
| case VT_INT: pElement = &variant.intVal; break; |
| case VT_UI1: Q_ASSERT(false); break; // already covered |
| case VT_UI2: pElement = &variant.uiVal; break; |
| case VT_UI4: pElement = &variant.ulVal; break; |
| case VT_UINT: pElement = &variant.uintVal; break; |
| case VT_CY: pElement = &variant.cyVal; break; |
| case VT_R4: pElement = &variant.fltVal; break; |
| case VT_R8: pElement = &variant.dblVal; break; |
| case VT_DATE: pElement = &variant.date; break; |
| case VT_VARIANT: Q_ASSERT(false); break; // already covered |
| default: |
| break; |
| } |
| if (!pElement) { |
| var = list; |
| break; |
| } |
| |
| long lBound, uBound; |
| SafeArrayGetLBound( array, 1, &lBound ); |
| SafeArrayGetUBound( array, 1, &uBound ); |
| |
| for ( long i = lBound; i <= uBound; ++i ) { |
| variant.vt = vt; |
| SafeArrayGetElement(array, &i, pElement); |
| QVariant qvar = VARIANTToQVariant(variant, nullptr); |
| clearVARIANT(&variant); |
| list << qvar; |
| } |
| |
| var = list; |
| } |
| break; |
| } |
| |
| QVariant::Type proptype = (QVariant::Type)type; |
| if (proptype == QVariant::Invalid && !typeName.isEmpty()) { |
| if (typeName != "QVariant") |
| proptype = QVariant::nameToType(typeName); |
| } |
| if (proptype != QVariant::Type(QMetaType::QVariant) && proptype != QVariant::LastType && proptype != QVariant::Invalid && var.type() != proptype) { |
| if (var.canConvert(proptype)) { |
| QVariant oldvar = var; |
| if (oldvar.convert(proptype)) |
| var = oldvar; |
| } else if (proptype == QVariant::StringList && var.type() == QVariant::List) { |
| bool allStrings = true; |
| QStringList strings; |
| const QVariantList list(var.toList()); |
| for (const QVariant &variant : list) { |
| if (variant.canConvert(QVariant::String)) |
| strings << variant.toString(); |
| else |
| allStrings = false; |
| } |
| if (allStrings) |
| var = strings; |
| } else { |
| var = QVariant(); |
| } |
| } |
| return var; |
| } |
| |
| QT_END_NAMESPACE |