summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJørn Bersvendsen <jornb87@gmail.com>2016-09-28 09:49:14 +0200
committerJørn Bersvendsen <jornb87@gmail.com>2016-10-19 20:48:34 +0000
commitd72a0b44812c38fc3ba9dd5b3deb87796b5c338a (patch)
treef70d1834064415adf5f1cc02d23d9faa9e421aa1
parent21fa3e04b0febc0fa0a84d01eacd3831fd6628f8 (diff)
Fixed cleanup of QApplication when unloading ActiveQt DLLv5.8.0-beta1
When an ActiveQt server starts, it creates a QApplication and tries to mimic the behavior of QCoreApplication::exec(). However, when destroying the QApplication in qaxserverdll.cpp DllCanUnloadNow(), it now performs the same cleanup as QCoreApplication::exec(). This is a partial fix for QTBUG-56172. Task-number: QTBUG-56172 Change-Id: Ibf8c411f8a1534beee61a738be3fd414de73f0ad Reviewed-by: Fredrik Orderud <forderud@gmail.com> Reviewed-by: Andy Shaw <andy.shaw@qt.io> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--src/activeqt/control/control.pro1
-rw-r--r--src/activeqt/control/qaxserverbase.cpp295
-rw-r--r--src/activeqt/control/qaxserverdll.cpp3
-rw-r--r--src/activeqt/control/qclassfactory_p.h100
4 files changed, 253 insertions, 146 deletions
diff --git a/src/activeqt/control/control.pro b/src/activeqt/control/control.pro
index b87c30e..6409112 100644
--- a/src/activeqt/control/control.pro
+++ b/src/activeqt/control/control.pro
@@ -10,6 +10,7 @@ mingw: DEFINES += QT_NEEDS_QMAIN
HEADERS = qaxaggregated.h \
qaxbindable.h \
qaxfactory.h \
+ qclassfactory_p.h \
../shared/qaxtypes.h
SOURCES = qaxaggregated.cpp \
diff --git a/src/activeqt/control/qaxserverbase.cpp b/src/activeqt/control/qaxserverbase.cpp
index 61645fd..663edf1 100644
--- a/src/activeqt/control/qaxserverbase.cpp
+++ b/src/activeqt/control/qaxserverbase.cpp
@@ -65,6 +65,9 @@
#include <qpa/qplatformnativeinterface.h>
#include <qabstractnativeeventfilter.h>
+#include <qcoreapplication.h>
+#include <private/qthread_p.h>
+
#include "qaxfactory.h"
#include "qaxbindable.h"
#include "qaxaggregated.h"
@@ -72,6 +75,8 @@
#include "../shared/qaxtypes.h"
#include "../shared/qaxutils_p.h"
+#include "qclassfactory_p.h"
+
#if defined Q_CC_GNU
# include <w32api.h>
#endif
@@ -831,182 +836,180 @@ Q_GLOBAL_STATIC(QAxWinEventFilter, qax_winEventFilter);
// COM Factory class, mapping COM requests to ActiveQt requests.
// One instance of this class for each ActiveX the server can provide.
-class QClassFactory : public IClassFactory2
+QClassFactory::QClassFactory(CLSID clsid)
+ : ref(0), licensed(false)
{
-public:
- QClassFactory(CLSID clsid)
- : ref(0), licensed(false)
- {
- InitializeCriticalSection(&refCountSection);
-
- // COM only knows the CLSID, but QAxFactory is class name based...
- QStringList keys = qAxFactory()->featureList();
- foreach (const QString &key, keys) {
- if (qAxFactory()->classID(key) == clsid) {
- className = key;
- break;
- }
- }
+ InitializeCriticalSection(&refCountSection);
- const QMetaObject *mo = qAxFactory()->metaObject(className);
- if (mo) {
- classKey = QLatin1String(mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value());
- licensed = !classKey.isEmpty();
+ // COM only knows the CLSID, but QAxFactory is class name based...
+ QStringList keys = qAxFactory()->featureList();
+ foreach (const QString &key, keys) {
+ if (qAxFactory()->classID(key) == clsid) {
+ className = key;
+ break;
}
}
- virtual ~QClassFactory()
- {
- DeleteCriticalSection(&refCountSection);
+ const QMetaObject *mo = qAxFactory()->metaObject(className);
+ if (mo) {
+ classKey = QLatin1String(mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value());
+ licensed = !classKey.isEmpty();
}
+}
- // IUnknown
- unsigned long WINAPI AddRef()
- {
- return InterlockedIncrement(&ref);
- }
- unsigned long WINAPI Release()
- {
- LONG refCount = InterlockedDecrement(&ref);
- if (!refCount)
- delete this;
+QClassFactory::~QClassFactory()
+{
+ DeleteCriticalSection(&refCountSection);
+}
- return refCount;
- }
- HRESULT WINAPI QueryInterface(REFIID iid, LPVOID *iface)
- {
- *iface = 0;
- if (iid == IID_IUnknown)
- *iface = static_cast<IUnknown *>(this);
- else if (iid == IID_IClassFactory)
- *iface = static_cast<IClassFactory *>(this);
- else if (iid == IID_IClassFactory2 && licensed)
- *iface = static_cast<IClassFactory2 *>(this);
- else
- return E_NOINTERFACE;
+// IUnknown
+unsigned long QClassFactory::AddRef()
+{
+ return InterlockedIncrement(&ref);
+}
- AddRef();
- return S_OK;
- }
+unsigned long QClassFactory::Release()
+{
+ LONG refCount = InterlockedDecrement(&ref);
+ if (!refCount)
+ delete this;
- HRESULT WINAPI CreateInstanceHelper(IUnknown *pUnkOuter, REFIID iid, void **ppObject)
- {
- if (pUnkOuter) {
- if (iid != IID_IUnknown)
- return CLASS_E_NOAGGREGATION;
- const QMetaObject *mo = qAxFactory()->metaObject(className);
- if (mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Aggregatable")).value(), "no"))
- return CLASS_E_NOAGGREGATION;
- }
+ return refCount;
+}
- // Make sure a QApplication instance is present (inprocess case)
- if (!qApp) {
- qax_ownQApp = true;
- int argc = 0;
- new QApplication(argc, 0);
- }
- QGuiApplication::setQuitOnLastWindowClosed(false);
+HRESULT QClassFactory::QueryInterface(REFIID iid, LPVOID *iface)
+{
+ *iface = 0;
+ if (iid == IID_IUnknown)
+ *iface = static_cast<IUnknown *>(this);
+ else if (iid == IID_IClassFactory)
+ *iface = static_cast<IClassFactory *>(this);
+ else if (iid == IID_IClassFactory2 && licensed)
+ *iface = static_cast<IClassFactory2 *>(this);
+ else
+ return E_NOINTERFACE;
- if (qAxOutProcServer)
- QAbstractEventDispatcher::instance()->installNativeEventFilter(qax_winEventFilter());
- else
- QApplication::instance()->d_func()->in_exec = true;
+ AddRef();
+ return S_OK;
+}
- // hook into eventloop; this allows a server to create his own QApplication object
- if (!qax_hhook && qax_ownQApp) {
- qax_hhook = SetWindowsHookEx(WH_GETMESSAGE, axs_FilterProc, 0, GetCurrentThreadId());
- }
+HRESULT QClassFactory::CreateInstanceHelper(IUnknown *pUnkOuter, REFIID iid, void **ppObject)
+{
+ if (pUnkOuter) {
+ if (iid != IID_IUnknown)
+ return CLASS_E_NOAGGREGATION;
+ const QMetaObject *mo = qAxFactory()->metaObject(className);
+ if (mo && !qstricmp(mo->classInfo(mo->indexOfClassInfo("Aggregatable")).value(), "no"))
+ return CLASS_E_NOAGGREGATION;
+ }
- // If we created QApplication instance, ensure native event loop starts properly
- // by calling processEvents.
- if (qax_ownQApp)
- QCoreApplication::processEvents();
-
- HRESULT res;
- // Create the ActiveX wrapper - aggregate if requested
- if (pUnkOuter) {
- QAxServerAggregate *aggregate = new QAxServerAggregate(className, pUnkOuter);
- res = aggregate->QueryInterface(iid, ppObject);
- if (FAILED(res))
- delete aggregate;
- } else {
- QAxServerBase *activeqt = new QAxServerBase(className, pUnkOuter);
- res = activeqt->QueryInterface(iid, ppObject);
- if (FAILED(res))
- delete activeqt;
- else
- activeqt->registerActiveObject((IUnknown*)(IDispatch*)activeqt);
- }
- return res;
+ // Make sure a QApplication instance is present (inprocess case)
+ if (!qApp) {
+ qax_ownQApp = true;
+ int argc = 0;
+ new QApplication(argc, 0);
}
+ QGuiApplication::setQuitOnLastWindowClosed(false);
- // IClassFactory
- HRESULT WINAPI CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppObject)
- {
- // class is licensed
- if (licensed && !qAxFactory()->validateLicenseKey(className, QString()))
- return CLASS_E_NOTLICENSED;
+ if (qAxOutProcServer)
+ QAbstractEventDispatcher::instance()->installNativeEventFilter(qax_winEventFilter());
+ else
+ QApplication::instance()->d_func()->in_exec = true;
- return CreateInstanceHelper(pUnkOuter, iid, ppObject);
+ // hook into eventloop; this allows a server to create his own QApplication object
+ if (!qax_hhook && qax_ownQApp) {
+ qax_hhook = SetWindowsHookEx(WH_GETMESSAGE, axs_FilterProc, 0, GetCurrentThreadId());
}
- HRESULT WINAPI LockServer(BOOL fLock)
- {
- if (fLock)
- qAxLock();
- else
- qAxUnlock();
- return S_OK;
+ // If we created QApplication instance, ensure native event loop starts properly
+ // by calling processEvents.
+ if (qax_ownQApp)
+ QCoreApplication::processEvents();
+
+ HRESULT res;
+ // Create the ActiveX wrapper - aggregate if requested
+ if (pUnkOuter) {
+ QAxServerAggregate *aggregate = new QAxServerAggregate(className, pUnkOuter);
+ res = aggregate->QueryInterface(iid, ppObject);
+ if (FAILED(res))
+ delete aggregate;
+ } else {
+ QAxServerBase *activeqt = new QAxServerBase(className, pUnkOuter);
+ res = activeqt->QueryInterface(iid, ppObject);
+ if (FAILED(res))
+ delete activeqt;
+ else
+ activeqt->registerActiveObject((IUnknown*)(IDispatch*)activeqt);
}
+ return res;
+}
- // IClassFactory2
- HRESULT WINAPI RequestLicKey(DWORD, BSTR *pKey)
- {
- if (!pKey)
- return E_POINTER;
- *pKey = 0;
+// IClassFactory
+HRESULT QClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppObject)
+{
+ // class is licensed
+ if (licensed && !qAxFactory()->validateLicenseKey(className, QString()))
+ return CLASS_E_NOTLICENSED;
- // This of course works only on fully licensed machines
- if (!qAxFactory()->validateLicenseKey(className, QString()))
- return CLASS_E_NOTLICENSED;
+ return CreateInstanceHelper(pUnkOuter, iid, ppObject);
+}
- *pKey = QStringToBSTR(classKey);
- return S_OK;
- }
+HRESULT QClassFactory::LockServer(BOOL fLock)
+{
+ if (fLock)
+ qAxLock();
+ else
+ qAxUnlock();
- HRESULT WINAPI GetLicInfo(LICINFO *pLicInfo)
- {
- if (!pLicInfo)
- return E_POINTER;
- pLicInfo->cbLicInfo = sizeof(LICINFO);
+ return S_OK;
+}
- // class specific license key?
- const QMetaObject *mo = qAxFactory()->metaObject(className);
- const char *key = mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value();
- pLicInfo->fRuntimeKeyAvail = key && key[0];
+// IClassFactory2
+HRESULT QClassFactory::RequestLicKey(DWORD, BSTR *pKey)
+{
+ if (!pKey)
+ return E_POINTER;
+ *pKey = 0;
- // machine fully licensed?
- pLicInfo->fLicVerified = qAxFactory()->validateLicenseKey(className, QString());
+ // This of course works only on fully licensed machines
+ if (!qAxFactory()->validateLicenseKey(className, QString()))
+ return CLASS_E_NOTLICENSED;
- return S_OK;
- }
+ *pKey = QStringToBSTR(classKey);
+ return S_OK;
+}
- HRESULT WINAPI CreateInstanceLic(IUnknown *pUnkOuter, IUnknown * /* pUnkReserved */, REFIID iid, BSTR bKey, PVOID *ppObject)
- {
- QString licenseKey = QString::fromWCharArray(bKey);
- if (!qAxFactory()->validateLicenseKey(className, licenseKey))
- return CLASS_E_NOTLICENSED;
- return CreateInstanceHelper(pUnkOuter, iid, ppObject);
- }
+HRESULT QClassFactory::GetLicInfo(LICINFO *pLicInfo)
+{
+ if (!pLicInfo)
+ return E_POINTER;
+ pLicInfo->cbLicInfo = sizeof(LICINFO);
- QString className;
+ // class specific license key?
+ const QMetaObject *mo = qAxFactory()->metaObject(className);
+ const char *key = mo->classInfo(mo->indexOfClassInfo("LicenseKey")).value();
+ pLicInfo->fRuntimeKeyAvail = key && key[0];
+
+ // machine fully licensed?
+ pLicInfo->fLicVerified = qAxFactory()->validateLicenseKey(className, QString());
+
+ return S_OK;
+}
+
+HRESULT QClassFactory::CreateInstanceLic(IUnknown *pUnkOuter, IUnknown * /* pUnkReserved */, REFIID iid, BSTR bKey, PVOID *ppObject)
+{
+ QString licenseKey = QString::fromWCharArray(bKey);
+ if (!qAxFactory()->validateLicenseKey(className, licenseKey))
+ return CLASS_E_NOTLICENSED;
+ return CreateInstanceHelper(pUnkOuter, iid, ppObject);
+}
+
+void QClassFactory::cleanupCreatedApplication(QCoreApplication &app)
+{
+ // Cleanup similar to QCoreApplication::exec()
+ app.d_func()->execCleanup();
+}
-protected:
- CRITICAL_SECTION refCountSection;
- LONG ref;
- bool licensed;
- QString classKey;
-};
// Create a QClassFactory object for class \a iid
HRESULT GetClassObject(REFIID clsid, REFIID iid, void **ppUnk)
diff --git a/src/activeqt/control/qaxserverdll.cpp b/src/activeqt/control/qaxserverdll.cpp
index 7117cbb..b0584d5 100644
--- a/src/activeqt/control/qaxserverdll.cpp
+++ b/src/activeqt/control/qaxserverdll.cpp
@@ -45,6 +45,8 @@
#include <qt_windows.h>
+#include "qclassfactory_p.h"
+
QT_BEGIN_NAMESPACE
bool qax_ownQApp = false;
@@ -111,6 +113,7 @@ STDAPI DllCanUnloadNow()
if (qax_hhook)
UnhookWindowsHookEx(qax_hhook);
+ QClassFactory::cleanupCreatedApplication(*qApp);
delete qApp;
qax_ownQApp = false;
diff --git a/src/activeqt/control/qclassfactory_p.h b/src/activeqt/control/qclassfactory_p.h
new file mode 100644
index 0000000..633c6f1
--- /dev/null
+++ b/src/activeqt/control/qclassfactory_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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$
+** 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$
+**
+****************************************************************************/
+
+#ifndef QCLASSFACTORY_P_H
+#define QCLASSFACTORY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qcoreapplication.h>
+#include <ocidl.h>
+
+QT_BEGIN_NAMESPACE
+
+// COM Factory class, mapping COM requests to ActiveQt requests.
+// One instance of this class for each ActiveX the server can provide.
+class QClassFactory : public IClassFactory2
+{
+public:
+ QClassFactory(CLSID clsid);
+
+ virtual ~QClassFactory();
+
+ // IUnknown
+ unsigned long WINAPI AddRef();
+ unsigned long WINAPI Release();
+ HRESULT WINAPI QueryInterface(REFIID iid, LPVOID *iface);
+
+ HRESULT WINAPI CreateInstanceHelper(IUnknown *pUnkOuter, REFIID iid, void **ppObject);
+
+ // IClassFactory
+ HRESULT WINAPI CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppObject);
+
+ HRESULT WINAPI LockServer(BOOL fLock);
+ // IClassFactory2
+ HRESULT WINAPI RequestLicKey(DWORD, BSTR *pKey);
+
+ HRESULT WINAPI GetLicInfo(LICINFO *pLicInfo);
+
+ HRESULT WINAPI CreateInstanceLic(IUnknown *pUnkOuter, IUnknown * /* pUnkReserved */, REFIID iid, BSTR bKey, PVOID *ppObject);
+
+ static void cleanupCreatedApplication(QCoreApplication &app);
+
+ QString className;
+
+protected:
+ CRITICAL_SECTION refCountSection;
+ LONG ref;
+ bool licensed;
+ QString classKey;
+};
+
+QT_END_NAMESPACE
+
+#endif // QCLASSFACTORY_P_H