summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/activeqt/simpleqml/simpleqml.def2
-rw-r--r--src/activeqt/container/qaxbase.cpp34
-rw-r--r--src/activeqt/container/qaxbase.h3
-rw-r--r--src/activeqt/container/qaxselect.cpp38
-rw-r--r--src/activeqt/container/qaxselect.h8
-rw-r--r--src/activeqt/container/qaxselect.ui23
-rw-r--r--src/activeqt/container/qaxwidget.cpp24
-rw-r--r--src/activeqt/control/qaxfactory.cpp5
-rw-r--r--src/activeqt/control/qaxserver.cpp18
-rw-r--r--src/activeqt/control/qaxserver.def12
-rw-r--r--src/activeqt/control/qaxserverbase.cpp13
-rw-r--r--src/activeqt/doc/snippets/src_activeqt_control_qaxfactory.cpp17
-rw-r--r--src/activeqt/doc/src/qtaxserver.qdoc8
-rw-r--r--tools/testcon/changeproperties.cpp6
-rw-r--r--tools/testcon/controlinfo.cpp4
-rw-r--r--tools/testcon/main.cpp13
-rw-r--r--tools/testcon/mainwindow.cpp77
-rw-r--r--tools/testcon/mainwindow.h9
19 files changed, 246 insertions, 70 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 1bf9543..f8cda0e 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,3 @@
load(qt_build_config)
-MODULE_VERSION = 5.12.3
+MODULE_VERSION = 5.13.0
diff --git a/examples/activeqt/simpleqml/simpleqml.def b/examples/activeqt/simpleqml/simpleqml.def
index b6ede3c..bc82a03 100644
--- a/examples/activeqt/simpleqml/simpleqml.def
+++ b/examples/activeqt/simpleqml/simpleqml.def
@@ -1,5 +1,3 @@
-; simpleqml.def : Declares the module parameters.
-
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp
index 722a389..bdd0c77 100644
--- a/src/activeqt/container/qaxbase.cpp
+++ b/src/activeqt/container/qaxbase.cpp
@@ -595,6 +595,7 @@ public:
QAxBasePrivate()
: useEventSink(true), useMetaObject(true), useClassInfo(true),
cachedMetaObject(false), initialized(false), tryCache(false),
+ classContext(CLSCTX_SERVER),
ptr(0), disp(0), metaobj(0)
{
// protect initialization
@@ -638,6 +639,7 @@ public:
uint cachedMetaObject :1;
uint initialized :1;
uint tryCache :1;
+ unsigned long classContext;
IUnknown *ptr;
mutable IDispatch *disp;
@@ -989,6 +991,8 @@ QAxMetaObject *QAxBase::internalMetaObject() const
The control's read function always returns the control's UUID, if provided including the license
key, and the name of the server, but not including the username, the domain or the password.
+
+ \sa setClassContext()
*/
bool QAxBase::setControl(const QString &c)
{
@@ -1067,6 +1071,34 @@ void QAxBase::disableEventSink()
}
/*!
+ \since 5.13
+
+ \return the context the ActiveX control will run in (default CLSCTX_SERVER).
+*/
+unsigned long QAxBase::classContext() const
+{
+ return d->classContext;
+}
+
+/*!
+ \since 5.13
+
+ Sets the context the ActiveX control will run in to \a classContext
+
+ Affects the "dwClsContext" argument when calling CoCreateInstance.
+ This can be used to control in-proc vs. out-of-proc startup for controls
+ supporting both alternatives. Also, it can be used to modify/reduce control
+ permissions when used with CLSCTX_ENABLE_CLOAKING and an impersonation token.
+
+ Note that this function must be called before setControl() to have any
+ effect.
+*/
+void QAxBase::setClassContext(unsigned long classContext)
+{
+ d->classContext = classContext;
+}
+
+/*!
Disables the meta object generation for this ActiveX container.
This also disables the event sink and class info generation. If
you don't intend to use the Qt meta object implementation call
@@ -1237,7 +1269,7 @@ bool QAxBase::initialize(IUnknown **ptr)
res = initializeFromFile(ptr);
if (!res) { // standard
- HRESULT hres = CoCreateInstance(QUuid(ctrl), 0, CLSCTX_SERVER, IID_IUnknown,
+ HRESULT hres = CoCreateInstance(QUuid(ctrl), 0, d->classContext, IID_IUnknown,
reinterpret_cast<void **>(ptr));
res = S_OK == hres;
#ifndef QT_NO_DEBUG
diff --git a/src/activeqt/container/qaxbase.h b/src/activeqt/container/qaxbase.h
index 78203f7..740fd6d 100644
--- a/src/activeqt/container/qaxbase.h
+++ b/src/activeqt/container/qaxbase.h
@@ -136,6 +136,9 @@ public:
void disableClassInfo();
void disableEventSink();
+ unsigned long classContext() const;
+ void setClassContext(unsigned long classContext);
+
protected:
virtual bool initialize(IUnknown** ptr);
bool initializeRemote(IUnknown** ptr);
diff --git a/src/activeqt/container/qaxselect.cpp b/src/activeqt/container/qaxselect.cpp
index 1b860e7..2f0f2aa 100644
--- a/src/activeqt/container/qaxselect.cpp
+++ b/src/activeqt/container/qaxselect.cpp
@@ -67,6 +67,20 @@
QT_BEGIN_NAMESPACE
+/*!
+ \since 5.13
+
+ \enum QAxSelect::SandboxingLevel
+
+ The SandboxingLevel enumeration defines the desired level of ActiveX sandboxing.
+
+ \value SandboxingNone No specific sandboxing desired
+ \value SandboxingProcess Run ActiveX control in a separate process
+ \value SandboxingLowIntegrity Run ActiveX control in a separate low-integrity process
+
+ Sandboxing requires that the ActiveX is either built as an EXE, or as a DLL with AppID "DllSurrogate" enabled.
+*/
+
enum ControlType { InProcessControl, OutOfProcessControl };
struct Control
@@ -327,8 +341,9 @@ public:
\inmodule QAxContainer
QAxSelect dialog can be used to provide users with a way to browse the registered COM
- components of the system and select one. The CLSID of the selected component can
- then be used in the application to e.g. initialize a QAxWidget:
+ components of the system and select one. It also provides a combo box for selecting
+ desired sandboxing level. The CLSID of the selected component can then be used in the
+ application to e.g. initialize a QAxWidget:
\snippet src_activeqt_container_qaxselect.cpp 0
@@ -359,6 +374,9 @@ QAxSelect::QAxSelect(QWidget *parent, Qt::WindowFlags flags)
d->filterModel->setSourceModel(new ControlList(this));
d->selectUi.ActiveXList->setModel(d->filterModel);
+ QStringList sandboxingOptions = { QLatin1String("None"), QLatin1String("Process isolation"), QLatin1String("Low integrity process") };
+ d->selectUi.SandboxingCombo->addItems(sandboxingOptions);
+
connect(d->selectUi.ActiveXList->selectionModel(), &QItemSelectionModel::currentChanged,
this, &QAxSelect::onActiveXListCurrentChanged);
connect(d->selectUi.ActiveXList, &QAbstractItemView::activated,
@@ -390,6 +408,22 @@ QString QAxSelect::clsid() const
return d->selectUi.ActiveX->text().trimmed();
}
+/*!
+ \since 5.13
+
+ Returns the desired level of sandboxing for the ActiveX control.
+*/
+QAxSelect::SandboxingLevel QAxSelect::sandboxingLevel() const
+{
+ int idx = d->selectUi.SandboxingCombo->currentIndex();
+ if (idx == 1)
+ return SandboxingProcess;
+ else if (idx == 2)
+ return SandboxingLowIntegrity;
+ else
+ return SandboxingNone;
+}
+
void QAxSelect::onActiveXListCurrentChanged(const QModelIndex &index)
{
const QString newClsid = d->clsidAt(index);
diff --git a/src/activeqt/container/qaxselect.h b/src/activeqt/container/qaxselect.h
index d17de95..960abd9 100644
--- a/src/activeqt/container/qaxselect.h
+++ b/src/activeqt/container/qaxselect.h
@@ -61,9 +61,17 @@ class QAxSelect : public QDialog
{
Q_OBJECT
public:
+ enum SandboxingLevel {
+ SandboxingNone = 0,
+ SandboxingProcess,
+ SandboxingLowIntegrity,
+ };
+
explicit QAxSelect(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
~QAxSelect() override;
+
QString clsid() const;
+ SandboxingLevel sandboxingLevel() const;
private Q_SLOTS:
void onActiveXListCurrentChanged(const QModelIndex &);
diff --git a/src/activeqt/container/qaxselect.ui b/src/activeqt/container/qaxselect.ui
index c6f3b0a..af5f973 100644
--- a/src/activeqt/container/qaxselect.ui
+++ b/src/activeqt/container/qaxselect.ui
@@ -96,6 +96,29 @@
</item>
</layout>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="unnamed2">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="TextLabel2">
+ <property name="text">
+ <string>Sandboxing:</string>
+ </property>
+ <property name="buddy">
+ <cstring>SandboxingCombo</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="SandboxingCombo"/>
+ </item>
+ </layout>
+ </item>
</layout>
</item>
<item>
diff --git a/src/activeqt/container/qaxwidget.cpp b/src/activeqt/container/qaxwidget.cpp
index b25e4b2..a28c64f 100644
--- a/src/activeqt/container/qaxwidget.cpp
+++ b/src/activeqt/container/qaxwidget.cpp
@@ -695,10 +695,32 @@ bool QAxClientSite::activateObject(bool initialized, const QByteArray &data)
RECT rcPos = qaxQRect2Rect(QRect(qaxNativeWidgetPosition(host), qaxToNativeSize(host, sizehint)));
+ const HWND hostWnd = reinterpret_cast<HWND>(host->winId());
m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, 0, static_cast<IOleClientSite *>(this), 0,
- reinterpret_cast<HWND>(host->winId()),
+ hostWnd,
&rcPos);
+ HWND controlWnd = {};
+ {
+ IOleWindow *oleWindow = nullptr;
+ m_spOleObject->QueryInterface(IID_IOleWindow, reinterpret_cast<void **>(&oleWindow));
+ if (oleWindow) {
+ oleWindow->GetWindow(&controlWnd);
+ oleWindow->Release();
+ }
+ }
+
+ if (controlWnd && !GetParent(controlWnd)) {
+ // re-parent control window
+ // this is necessary if the control is running in a "low integrity" process that isn't
+ // permitted to create a child window with hostWnd as parent
+ int winStyle = GetWindowLongPtr(controlWnd, GWL_STYLE);
+ winStyle &= ~WS_CAPTION; // remove title bar
+ winStyle |= WS_CHILD; // convert to child window
+ SetWindowLongPtr(controlWnd, GWL_STYLE, winStyle);
+ SetParent(controlWnd, hostWnd);
+ }
+
if (!m_spOleControl)
m_spOleObject->QueryInterface(IID_IOleControl, reinterpret_cast<void **>(&m_spOleControl));
if (m_spOleControl) {
diff --git a/src/activeqt/control/qaxfactory.cpp b/src/activeqt/control/qaxfactory.cpp
index 2a0ed4f..0dbbd25 100644
--- a/src/activeqt/control/qaxfactory.cpp
+++ b/src/activeqt/control/qaxfactory.cpp
@@ -82,11 +82,6 @@ extern wchar_t qAxModuleFilename[MAX_PATH];
\snippet src_activeqt_control_qaxfactory.cpp 1
- If your server supports just a single COM object, you can use
- a default factory implementation through the \c QAXFACTORY_DEFAULT() macro.
-
- \snippet src_activeqt_control_qaxfactory.cpp 2
-
Only one QAxFactory implementation may be instantiated and
exported by an ActiveX server application. This instance is accessible
through the global qAxFactory() function.
diff --git a/src/activeqt/control/qaxserver.cpp b/src/activeqt/control/qaxserver.cpp
index ee55f09..8ae62a2 100644
--- a/src/activeqt/control/qaxserver.cpp
+++ b/src/activeqt/control/qaxserver.cpp
@@ -283,10 +283,11 @@ HRESULT UpdateRegistry(BOOL bRegister)
}
if (bRegister) {
- if (qAxOutProcServer) {
- settings->setValue(QLatin1String("/AppID/") + appId + QLatin1String("/."), module);
+ settings->setValue(QLatin1String("/AppID/") + appId + QLatin1String("/."), module);
+ if (qAxOutProcServer)
settings->setValue(QLatin1String("/AppID/") + module + QLatin1String(".EXE/AppID"), appId);
- }
+ else
+ settings->setValue(QLatin1String("/AppID/") + appId + QLatin1String("/DllSurrogate"), QString());
const QStringList keys = qAxFactory()->featureList();
for (const QString &classNameIn : keys) {
@@ -328,8 +329,7 @@ HRESULT UpdateRegistry(BOOL bRegister)
key = QLatin1String("/CLSID/") + classId;
settings->setValue(key + QLatin1String("/."), className + QLatin1String(" Class"));
- if (file.endsWith(QLatin1String("exe"), Qt::CaseInsensitive))
- settings->setValue(key + QLatin1String("/AppID"), appId);
+ settings->setValue(key + QLatin1String("/AppID"), appId);
if (control)
settings->setValue(key + QLatin1String("/Control/."), QVariant(QLatin1String("")));
if (insertable)
@@ -390,10 +390,12 @@ HRESULT UpdateRegistry(BOOL bRegister)
qAxFactory()->registerClass(classNameIn, settings.data());
}
} else {
- if (qAxOutProcServer) {
- settings->remove(QLatin1String("/AppID/") + appId + QLatin1String("/."));
+ settings->remove(QLatin1String("/AppID/") + appId + QLatin1String("/."));
+ if (qAxOutProcServer)
settings->remove(QLatin1String("/AppID/") + module + QLatin1String(".EXE"));
- }
+ else
+ settings->remove(QLatin1String("/AppID/") + appId + QLatin1String("/DllSurrogate"));
+
const QStringList keys = qAxFactory()->featureList();
for (const QString &classNameIn : keys) {
const QMetaObject *mo = qAxFactory()->metaObject(classNameIn);
diff --git a/src/activeqt/control/qaxserver.def b/src/activeqt/control/qaxserver.def
index a00638d..bc82a03 100644
--- a/src/activeqt/control/qaxserver.def
+++ b/src/activeqt/control/qaxserver.def
@@ -1,8 +1,6 @@
-; mfc_test.def : Declares the module parameters.
-
EXPORTS
- DllCanUnloadNow PRIVATE
- DllGetClassObject PRIVATE
- DllRegisterServer PRIVATE
- DllUnregisterServer PRIVATE
- DumpIDL PRIVATE
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
+ DumpIDL PRIVATE
diff --git a/src/activeqt/control/qaxserverbase.cpp b/src/activeqt/control/qaxserverbase.cpp
index d11fbeb..4d277b6 100644
--- a/src/activeqt/control/qaxserverbase.cpp
+++ b/src/activeqt/control/qaxserverbase.cpp
@@ -1644,12 +1644,25 @@ HWND QAxServerBase::create(HWND hWndParent, RECT& rcPos)
}
Q_ASSERT(!m_hWnd);
+ // will fail if parent window belongs to a higher integrity level process
HWND hWnd = ::CreateWindow(reinterpret_cast<const wchar_t *>(cn.utf16()), 0,
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
rcPos.left, rcPos.top, rcPos.right - rcPos.left,
rcPos.bottom - rcPos.top, hWndParent, 0, hInst, this);
// m_hWnd is assigned in reponse to WM_CREATE
if (!hWnd) {
+ DWORD err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ // retry without parent window
+ // the window will now need to be re-parented in the container process
+ hWnd = ::CreateWindow(reinterpret_cast<const wchar_t *>(cn.utf16()), 0,
+ WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ rcPos.left, rcPos.top, rcPos.right - rcPos.left,
+ rcPos.bottom - rcPos.top, nullptr, 0, hInst, this);
+ }
+ }
+
+ if (!hWnd) {
qErrnoWarning("%s: CreateWindow() failed", __FUNCTION__);
return nullptr;
}
diff --git a/src/activeqt/doc/snippets/src_activeqt_control_qaxfactory.cpp b/src/activeqt/doc/snippets/src_activeqt_control_qaxfactory.cpp
index edc6489..73748e0 100644
--- a/src/activeqt/doc/snippets/src_activeqt_control_qaxfactory.cpp
+++ b/src/activeqt/doc/snippets/src_activeqt_control_qaxfactory.cpp
@@ -117,23 +117,6 @@ QAXFACTORY_END()
//! [1]
-//! [2]
-#include <qapplication.h>
-#include <qaxfactory.h>
-
-#include "theactivex.h"
-
-QAXFACTORY_DEFAULT(
- TheActiveX, // widget class
- "{01234567-89AB-CDEF-0123-456789ABCDEF}", // class ID
- "{01234567-89AB-CDEF-0123-456789ABCDEF}", // interface ID
- "{01234567-89AB-CDEF-0123-456789ABCDEF}", // event interface ID
- "{01234567-89AB-CDEF-0123-456789ABCDEF}", // type library ID
- "{01234567-89AB-CDEF-0123-456789ABCDEF}" // application ID
-)
-//! [2]
-
-
//! [3]
settings->setValue("/CLSID/" + classID(key)
+ "/Implemented Categories/"
diff --git a/src/activeqt/doc/src/qtaxserver.qdoc b/src/activeqt/doc/src/qtaxserver.qdoc
index 1f1db10..c9f4adc 100644
--- a/src/activeqt/doc/src/qtaxserver.qdoc
+++ b/src/activeqt/doc/src/qtaxserver.qdoc
@@ -225,14 +225,6 @@
Declare a standard constructor taking a parent object, and functions,
signals and slots like for any QObject subclass.
- \footnote
- If a standard constructor is not present the compiler will issue
- an error "no overloaded function takes 2 parameters" when using
- the default factory through the QAXFACTORY_DEFAULT() macro. If you
- cannot provide a standard constructor you must implement a
- QAxFactory custom factory and call the constructor you have in
- your implementation of \l {QAxFactory::createObject}.
- \endfootnote
\snippet doc_src_qaxserver.cpp 6
diff --git a/tools/testcon/changeproperties.cpp b/tools/testcon/changeproperties.cpp
index cae1f84..9b5cca2 100644
--- a/tools/testcon/changeproperties.cpp
+++ b/tools/testcon/changeproperties.cpp
@@ -202,9 +202,9 @@ void ChangeProperties::updateProperties()
item->setText(0, QString::fromLatin1(property.name()));
item->setText(1, QString::fromLatin1(property.typeName()));
if (!property.isDesignable()) {
- item->setTextColor(0, Qt::gray);
- item->setTextColor(1, Qt::gray);
- item->setTextColor(2, Qt::gray);
+ item->setForeground(0, Qt::gray);
+ item->setForeground(1, Qt::gray);
+ item->setForeground(2, Qt::gray);
}
QVariant var = activex->property(property.name());
diff --git a/tools/testcon/controlinfo.cpp b/tools/testcon/controlinfo.cpp
index 5782c7d..4c19fd1 100644
--- a/tools/testcon/controlinfo.cpp
+++ b/tools/testcon/controlinfo.cpp
@@ -99,8 +99,8 @@ void ControlInfo::setControl(QWidget *activex)
item->setText(0, QString::fromLatin1(property.name()));
item->setText(1, QString::fromLatin1(property.typeName()));
if (!property.isDesignable()) {
- item->setTextColor(0, Qt::gray);
- item->setTextColor(1, Qt::gray);
+ item->setForeground(0, Qt::gray);
+ item->setForeground(1, Qt::gray);
}
}
group->setText(1, QString::number(count));
diff --git a/tools/testcon/main.cpp b/tools/testcon/main.cpp
index 2454084..7c2ca07 100644
--- a/tools/testcon/main.cpp
+++ b/tools/testcon/main.cpp
@@ -35,12 +35,11 @@
#include <QDebug>
#include <QDesktopWidget>
-QAXFACTORY_DEFAULT(MainWindow,
- QLatin1String("{5f5ce700-48a8-47b1-9b06-3b7f79e41d7c}"),
- QLatin1String("{3fc86f5f-8b15-4428-8f6b-482bae91f1ae}"),
- QLatin1String("{02a268cd-24b4-4fd9-88ff-b01b683ef39d}"),
- QLatin1String("{4a43e44d-9d1d-47e5-a1e5-58fe6f7be0a4}"),
- QLatin1String("{16ee5998-77d2-412f-ad91-8596e29f123f}"))
+QAXFACTORY_BEGIN(
+ "{4a43e44d-9d1d-47e5-a1e5-58fe6f7be0a4}", // type library ID
+ "{16ee5998-77d2-412f-ad91-8596e29f123f}") // application ID
+ QAXCLASS(MainWindow)
+QAXFACTORY_END()
QT_USE_NAMESPACE
@@ -98,7 +97,7 @@ int main( int argc, char **argv )
const QStringList positionalArguments = parser.positionalArguments();
for (const QString &a : positionalArguments) {
if (a.startsWith(QLatin1Char('{')) && a.endsWith(QLatin1Char('}')))
- mw.addControlFromClsid(a);
+ mw.addControlFromClsid(a, QAxSelect::SandboxingNone);
else
mw.addControlFromFile(a);
}
diff --git a/tools/testcon/mainwindow.cpp b/tools/testcon/mainwindow.cpp
index 06ce0a0..0c3d3e8 100644
--- a/tools/testcon/mainwindow.cpp
+++ b/tools/testcon/mainwindow.cpp
@@ -45,9 +45,10 @@
#include <QtCore/QLibraryInfo>
#include <QtCore/qt_windows.h>
#include <ActiveQt/QAxScriptManager>
-#include <ActiveQt/QAxSelect>
#include <ActiveQt/QAxWidget>
#include <ActiveQt/qaxtypes.h>
+#include <memory>
+#include <sddl.h>
QT_BEGIN_NAMESPACE
@@ -118,10 +119,75 @@ QList<QAxWidget *> MainWindow::axWidgets() const
return result;
}
-bool MainWindow::addControlFromClsid(const QString &clsid)
+
+/** RAII class for temporarily impersonating low-integrity level for the current thread.
+ Intended to be used together with CLSCTX_ENABLE_CLOAKING when creating COM objects.
+ Based on "Designing Applications to Run at a Low Integrity Level" https://msdn.microsoft.com/en-us/library/bb625960.aspx */
+struct LowIntegrity {
+ LowIntegrity()
+ {
+ HANDLE cur_token = nullptr;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, &cur_token))
+ abort();
+
+ if (!DuplicateTokenEx(cur_token, 0, NULL, SecurityImpersonation, TokenPrimary, &m_token))
+ abort();
+
+ CloseHandle(cur_token);
+
+ PSID li_sid = nullptr;
+ if (!ConvertStringSidToSid(L"S-1-16-4096", &li_sid)) // low integrity SID
+ abort();
+
+ // reduce process integrity level
+ TOKEN_MANDATORY_LABEL TIL = {};
+ TIL.Label.Attributes = SE_GROUP_INTEGRITY;
+ TIL.Label.Sid = li_sid;
+ if (!SetTokenInformation(m_token, TokenIntegrityLevel, &TIL, sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(li_sid)))
+ abort();
+
+ if (!ImpersonateLoggedOnUser(m_token)) // change current thread integrity
+ abort();
+
+ LocalFree(li_sid);
+ li_sid = nullptr;
+ }
+
+ ~LowIntegrity()
+ {
+ if (!RevertToSelf())
+ abort();
+
+ CloseHandle(m_token);
+ m_token = nullptr;
+ }
+
+private:
+ HANDLE m_token = nullptr;
+};
+
+bool MainWindow::addControlFromClsid(const QString &clsid, QAxSelect::SandboxingLevel sandboxing)
{
QAxWidget *container = new QAxWidget;
- const bool result = container->setControl(clsid);
+
+ bool result = false;
+ {
+ std::unique_ptr<LowIntegrity> low_integrity;
+
+ if (sandboxing == QAxSelect::SandboxingProcess) {
+ // require out-of-process
+ container->setClassContext(CLSCTX_LOCAL_SERVER);
+ } else if (sandboxing == QAxSelect::SandboxingLowIntegrity) {
+ // impersonate "low integrity"
+ low_integrity.reset(new LowIntegrity);
+ // require out-of-process and
+ // propagate integrity level when calling setControl
+ container->setClassContext(CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING);
+ }
+
+ result = container->setControl(clsid);
+ }
+
if (result) {
container->setObjectName(container->windowTitle());
m_mdiArea->addSubWindow(container);
@@ -154,7 +220,8 @@ void MainWindow::appendLogText(const QString &message)
void MainWindow::on_actionFileNew_triggered()
{
QAxSelect select(this);
- while (select.exec() && !addControlFromClsid(select.clsid())) { }
+ while (select.exec() && !addControlFromClsid(select.clsid(), select.sandboxingLevel())) {
+ }
}
void MainWindow::on_actionFileLoad_triggered()
@@ -327,7 +394,7 @@ void MainWindow::on_actionControlPixmap_triggered()
return;
QLabel *label = new QLabel;
- label->setPixmap(QPixmap::grabWidget(container));
+ label->setPixmap(container->grab());
QMdiSubWindow *subWindow = m_mdiArea->addSubWindow(label);
subWindow->setWindowTitle(tr("%1 - Pixmap").arg(container->windowTitle()));
label->show();
diff --git a/tools/testcon/mainwindow.h b/tools/testcon/mainwindow.h
index 7e6575b..e980d06 100644
--- a/tools/testcon/mainwindow.h
+++ b/tools/testcon/mainwindow.h
@@ -29,6 +29,8 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
+#include <ActiveQt/QAxSelect>
+
#include "ui_mainwindow.h"
QT_BEGIN_NAMESPACE
@@ -48,13 +50,18 @@ QT_USE_NAMESPACE
class MainWindow : public QMainWindow, public Ui::MainWindow
{
Q_OBJECT
+
+ Q_CLASSINFO("ClassID", "{5f5ce700-48a8-47b1-9b06-3b7f79e41d7c}")
+ Q_CLASSINFO("InterfaceID", "{3fc86f5f-8b15-4428-8f6b-482bae91f1ae}")
+ Q_CLASSINFO("EventsID", "{02a268cd-24b4-4fd9-88ff-b01b683ef39d}")
+
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow *instance() { return m_instance; }
- bool addControlFromClsid(const QString &clsid);
+ bool addControlFromClsid(const QString &clsid, QAxSelect::SandboxingLevel sandboxing);
bool addControlFromFile(const QString &fileName);
bool loadScript(const QString &file);