aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/iqmodelindex.h67
-rw-r--r--include/iqvariant.h73
-rw-r--r--include/qdotnetabstractlistmodel.h241
-rw-r--r--include/qdotnetadapter.h39
-rw-r--r--include/qdotnetarray.h4
-rw-r--r--include/qdotnetcallback.h80
-rw-r--r--include/qdotnetdelegate.h37
-rw-r--r--include/qdotnetevent.h3
-rw-r--r--include/qdotnethost.h205
-rw-r--r--include/qdotnethostfxr.h34
-rw-r--r--include/qdotnetinterface.h111
-rw-r--r--include/qdotnetobject.h65
-rw-r--r--include/qdotnetref.h31
-rw-r--r--include/qdotnetstatic.h53
-rw-r--r--include/qdotnettype.h75
15 files changed, 934 insertions, 184 deletions
diff --git a/include/iqmodelindex.h b/include/iqmodelindex.h
new file mode 100644
index 0000000..84dd309
--- /dev/null
+++ b/include/iqmodelindex.h
@@ -0,0 +1,67 @@
+/***************************************************************************************************
+ Copyright (C) 2024 The Qt Company Ltd.
+ SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+***************************************************************************************************/
+
+#pragma once
+
+#include "qdotnetinterface.h"
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wconversion"
+#endif
+#include <QModelIndex>
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+#include <functional>
+
+struct IQModelIndex : public QDotNetNativeInterface<QModelIndex>
+{
+ static inline const QString &AssemblyQualifiedName =
+ QStringLiteral("Qt.DotNet.IQModelIndex, Qt.DotNet.Adapter");
+
+ IQModelIndex(const void *objectRef = nullptr)
+ : QDotNetNativeInterface<QModelIndex>(objectRef)
+ {
+ }
+
+ IQModelIndex(const QModelIndex &idx)
+ : QDotNetNativeInterface<QModelIndex>(AssemblyQualifiedName, new QModelIndex(idx), true)
+ {
+ init();
+ }
+
+ IQModelIndex(bool doCleanUp)
+ : QDotNetNativeInterface<QModelIndex>(AssemblyQualifiedName, new QModelIndex(), doCleanUp)
+ {
+ init();
+ }
+
+ void init() {
+ setCallback<bool>("IsValid", [this](void *data)
+ {
+ return reinterpret_cast<QModelIndex *>(data)->isValid();
+ });
+ setCallback<int>("Column", [this](void *data)
+ {
+ return reinterpret_cast<QModelIndex *>(data)->column();
+ });
+ setCallback<int>("Row", [this](void *data)
+ {
+ return reinterpret_cast<QModelIndex *>(data)->row();
+ });
+ setCallback<void *>("InternalPointer", [this](void *data)
+ {
+ return reinterpret_cast<QModelIndex *>(data)->internalPointer();
+ });
+ }
+
+ static void staticInit(QDotNetInterface *sta)
+ {
+ sta->setCallback<IQModelIndex>("QModelIndex_Create",
+ [](void *) { return IQModelIndex(true); });
+ }
+};
diff --git a/include/iqvariant.h b/include/iqvariant.h
new file mode 100644
index 0000000..255b082
--- /dev/null
+++ b/include/iqvariant.h
@@ -0,0 +1,73 @@
+/***************************************************************************************************
+ Copyright (C) 2024 The Qt Company Ltd.
+ SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+***************************************************************************************************/
+
+#pragma once
+
+#include "qdotnetinterface.h"
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wconversion"
+#endif
+#include <QVariant>
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+#include <functional>
+
+struct IQVariant : public QDotNetNativeInterface<QVariant>
+{
+ static inline const QString &AssemblyQualifiedName =
+ QStringLiteral("Qt.DotNet.IQVariant, Qt.DotNet.Adapter");
+
+ IQVariant(const void *objectRef = nullptr)
+ : QDotNetNativeInterface<QVariant>(objectRef)
+ {
+ }
+
+ IQVariant(QVariant &value, bool doCleanUp = false)
+ : QDotNetNativeInterface<QVariant>(AssemblyQualifiedName, &value, doCleanUp)
+ {
+ init();
+ }
+
+ IQVariant(const QString &value, bool doCleanUp = true)
+ : QDotNetNativeInterface<QVariant>(AssemblyQualifiedName, new QVariant(value), doCleanUp)
+ {
+ init();
+ }
+
+ IQVariant(bool doCleanUp)
+ : QDotNetNativeInterface<QVariant>(AssemblyQualifiedName, new QVariant(), doCleanUp)
+ {
+ init();
+ }
+
+ void init() {
+ setCallback<QString>("ToStringValue", [this](void *data)
+ {
+ QVariant *v = reinterpret_cast<QVariant *>(data);
+ if (!v)
+ return QString();
+ return v->toString();
+ });
+ setCallback<void, QString>("SetValue", [this](void *data, const auto &newValue)
+ {
+ QVariant *v = reinterpret_cast<QVariant *>(data);
+ if (!v)
+ return;
+ v->setValue(newValue);
+ });
+ }
+
+ static void staticInit(QDotNetInterface *sta)
+ {
+ sta->setCallback<IQVariant, QString>("QVariant_Create",
+ [](void *, QString value) { return IQVariant(value, true); });
+ sta->setCallback<IQVariant>("QVariant_Create",
+ [](void *) { return IQVariant(true); });
+ }
+};
diff --git a/include/qdotnetabstractlistmodel.h b/include/qdotnetabstractlistmodel.h
new file mode 100644
index 0000000..d917d37
--- /dev/null
+++ b/include/qdotnetabstractlistmodel.h
@@ -0,0 +1,241 @@
+/***************************************************************************************************
+ Copyright (C) 2024 The Qt Company Ltd.
+ SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+***************************************************************************************************/
+
+#pragma once
+
+#include "qdotnetinterface.h"
+#include "qdotnetobject.h"
+#include "qdotnetarray.h"
+#include "iqvariant.h"
+#include "iqmodelindex.h"
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wconversion"
+#endif
+#include <QAbstractListModel>
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+#include <functional>
+
+template<typename Base>
+struct IQAbstractListModel : public QDotNetNativeInterface<QAbstractListModel>
+{
+ static inline const QString &AssemblyQualifiedName =
+ QStringLiteral("Qt.DotNet.IQAbstractListModel, Qt.DotNet.Adapter");
+
+ IQAbstractListModel(Base *self)
+ : QDotNetNativeInterface<QAbstractListModel>(AssemblyQualifiedName, self, false)
+ {
+ setCallback<int, IQModelIndex>(
+ "Flags", [this](void *selfPtr, IQModelIndex index)
+ {
+ Base &self = *reinterpret_cast<Base *>(selfPtr);
+ return (int)self.base_flags(index);
+ });
+ setCallback<bool, IQModelIndex, IQVariant, int>(
+ "SetData", [this](void *selfPtr, IQModelIndex index, IQVariant value, int role)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ return self->base_setData(index, value, role);
+ });
+ setCallback<bool, int, int, IQModelIndex>(
+ "InsertRows", [this](void *selfPtr, int row, int count, IQModelIndex parent)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ return self->base_insertRows(row, count, parent);
+ });
+ setCallback<bool, int, int, IQModelIndex>(
+ "RemoveRows", [this](void *selfPtr, int row, int count, IQModelIndex parent)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ return self->base_removeRows(row, count, parent);
+ });
+ setCallback<void, IQModelIndex, int, int>(
+ "BeginInsertRows", [this](void *selfPtr, IQModelIndex parent, int first, int last)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ self->base_beginInsertRows(parent, first, last);
+ });
+ setCallback<void>(
+ "EndInsertRows", [this](void *selfPtr)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ self->base_endInsertRows();
+ });
+ setCallback<void, IQModelIndex, int, int>(
+ "BeginRemoveRows", [this](void *selfPtr, IQModelIndex parent, int first, int last)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ self->base_beginRemoveRows(parent, first, last);
+ });
+ setCallback<void>(
+ "EndRemoveRows", [this](void *selfPtr)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ self->base_endRemoveRows();
+ });
+ setCallback<IQModelIndex, int, int, void *>(
+ "CreateIndex", [this](void *selfPtr, int row, int col, void *ptr)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ return IQModelIndex(self->base_createIndex(row, col, ptr));
+ });
+ setCallback<void, IQModelIndex, IQModelIndex, QDotNetArray<int>>(
+ "EmitDataChanged", [this](void *selfPtr,
+ IQModelIndex topLeft, IQModelIndex bottomRight, QDotNetArray<int> roles)
+ {
+ auto *self = reinterpret_cast<Base *>(selfPtr);
+ if (roles.isValid()) {
+ QList<int> listRoles(roles.length());
+ for (int i = 0; i < roles.length(); ++i)
+ listRoles[i] = roles[i];
+ self->emit_base_dataChanged(topLeft, bottomRight, listRoles);
+ }
+ else {
+ self->emit_base_dataChanged(topLeft, bottomRight);
+ }
+ });
+ }
+};
+
+class QDotNetAbstractListModel : public QAbstractListModel, public QDotNetObject
+{
+
+public:
+ using IBase = IQAbstractListModel<QDotNetAbstractListModel>;
+ Q_DOTNET_OBJECT_REF_INLINE(QDotNetAbstractListModel, Q_DOTNET_OBJECT_INIT(base(this)))
+ Q_DOTNET_OBJECT_COPY_INLINE(QDotNetAbstractListModel, Q_DOTNET_OBJECT_INIT(base(this)))
+
+ QDotNetAbstractListModel(QDotNetObject &&movSrc) noexcept
+ : QDotNetObject(std::move(movSrc)), base(this)
+ {}
+
+ QDotNetAbstractListModel &operator=(QDotNetObject &&movSrc) noexcept
+ {
+ QDotNetObject::operator=(std::move(movSrc));
+ return *this;
+ }
+
+ static void staticInit(QDotNetInterface *sta)
+ {
+ sta->setCallback<IBase, QDotNetObject>("QAbstractListModel_Create",
+ [](void *, QDotNetObject self)
+ {
+ auto *obj = new QDotNetAbstractListModel(std::move(self));
+ return obj->base;
+ });
+ }
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override
+ {
+ return method("RowCount", fnRowCount).invoke(*this, parent);
+ }
+ int base_rowCount(const QModelIndex &parent = QModelIndex()) const
+ {
+ return QAbstractListModel::rowCount(parent);
+ }
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
+ {
+ return method("Data", fnData).invoke(*this, index, role);
+ }
+ QVariant base_data(const QModelIndex &index, int role = Qt::DisplayRole) const
+ {
+ return QAbstractListModel::data(index, role);
+ }
+
+ Qt::ItemFlags flags(const QModelIndex &index) const override
+ {
+ return Qt::ItemFlags::fromInt(method("Flags", fnFlags).invoke(*this, index));
+ }
+ Qt::ItemFlags base_flags(const QModelIndex &index) const
+ {
+ return QAbstractListModel::flags(index);
+ }
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
+ {
+ return method("SetData", fnSetData)
+ .invoke(*this, index, const_cast<std::remove_const_t<QVariant &>>(value), role);
+ }
+ bool base_setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
+ {
+ return QAbstractListModel::setData(index, value, role);
+ }
+
+ bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override
+ {
+ return method("InsertRows", fnInsertRows).invoke(*this, row, count, parent);
+ }
+ bool base_insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
+ {
+ return QAbstractListModel::insertRows(row, count, parent);
+ }
+
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override
+ {
+ return method("RemoveRows", fnRemoveRows).invoke(*this, row, count, parent);
+ }
+ bool base_removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
+ {
+ return QAbstractListModel::removeRows(row, count, parent);
+ }
+
+ QHash<int, QByteArray> roleNames() const override
+ {
+ auto names = method("RoleNames", fnRoleNames).invoke(*this);
+ if (names.isEmpty())
+ return QAbstractListModel::roleNames();
+ auto nameList = names.split(u',', Qt::SkipEmptyParts);
+ QHash<int, QByteArray> roles;
+ for (int i = 0; i < nameList.size(); ++i)
+ roles[Qt::UserRole + i + 1] = nameList[i].toUtf8();
+ return roles;
+ }
+
+ void base_beginInsertRows(const QModelIndex &parent, int first, int last)
+ {
+ QAbstractListModel::beginInsertRows(parent, first, last);
+ }
+
+ void base_endInsertRows()
+ {
+ QAbstractListModel::endInsertRows();
+ }
+
+ void base_beginRemoveRows(const QModelIndex &parent, int first, int last)
+ {
+ QAbstractListModel::beginRemoveRows(parent, first, last);
+ }
+
+ void base_endRemoveRows()
+ {
+ QAbstractListModel::endRemoveRows();
+ }
+
+ QModelIndex base_createIndex(int arow, int acolumn, const void *adata) const
+ {
+ return QAbstractListModel::createIndex(arow, acolumn, adata);
+ }
+
+ void emit_base_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles = QList<int>())
+ {
+ emit QAbstractListModel::dataChanged(topLeft, bottomRight, roles);
+ }
+
+protected:
+ IBase base;
+ mutable QDotNetFunction<int, IQModelIndex> fnFlags = nullptr;
+ mutable QDotNetFunction<int, IQModelIndex> fnRowCount = nullptr;
+ mutable QDotNetFunction<IQVariant, IQModelIndex, int> fnData = nullptr;
+ mutable QDotNetFunction<bool, IQModelIndex, IQVariant, int> fnSetData = nullptr;
+ mutable QDotNetFunction<bool, int, int, IQModelIndex> fnInsertRows = nullptr;
+ mutable QDotNetFunction<bool, int, int, IQModelIndex> fnRemoveRows = nullptr;
+ mutable QDotNetFunction<QString> fnRoleNames = nullptr;
+};
diff --git a/include/qdotnetadapter.h b/include/qdotnetadapter.h
index fc9b74e..d9b5b95 100644
--- a/include/qdotnetadapter.h
+++ b/include/qdotnetadapter.h
@@ -33,6 +33,14 @@ private:
~QDotNetAdapter()
{
+ if (staticInterface && dtor_staticInterface) {
+ dtor_staticInterface(staticInterface);
+ staticInterface = nullptr;
+ }
+ fnReset();
+ //gcCollect();
+ //gcWaitForPendingFinalizers();
+
defaultHost.unload();
}
@@ -53,6 +61,12 @@ public:
.filePath(defaultDllName), defaultAssemblyName, defaultTypeName, externalHost);
}
+ static void init(const QString &assemblyPath, const QString &typeAndAssemblyName,
+ QDotNetHost *externalHost = nullptr)
+ {
+ init(assemblyPath, typeAndAssemblyName, typeAndAssemblyName, externalHost);
+ }
+
static void init(const QString &assemblyPath, const QString &assemblyName,
const QString &typeName, QDotNetHost *externalHost = nullptr)
{
@@ -92,10 +106,18 @@ public:
host->resolveFunction(QDOTNETADAPTER_DELEGATE(SetInterfaceMethod));
host->resolveFunction(QDOTNETADAPTER_DELEGATE(Stats));
host->resolveFunction(QDOTNETADAPTER_DELEGATE(GetObject));
+ host->resolveFunction(QDOTNETADAPTER_DELEGATE(Reset));
#undef QDOTNETADAPTER_DELEGATE
instance().host = host;
+
+ if (ctor_staticInterface)
+ instance().staticInterface = ctor_staticInterface();
+ gcCollect = instance().resolveStaticMethod("System.GC, System.Runtime",
+ "Collect", { QDotNetInbound<void>::Parameter });
+ gcWaitForPendingFinalizers = instance().resolveStaticMethod("System.GC, System.Runtime",
+ "WaitForPendingFinalizers", { QDotNetInbound<void>::Parameter });
}
static QDotNetAdapter &instance()
@@ -225,12 +247,12 @@ public:
fnFreeTypeRef(typeName);
}
- void *addInterfaceProxy(const QString &interfaceName) const
+ void *addInterfaceProxy(const QString &interfaceName, void *data, void *cleanUp) const
{
init();
if (interfaceName.isEmpty())
return nullptr;
- return fnAddInterfaceProxy(interfaceName);
+ return fnAddInterfaceProxy(interfaceName, data, cleanUp);
}
void setInterfaceMethod(const QDotNetRef &obj, const QString &methodName,
@@ -261,6 +283,8 @@ public:
Stats s{ };
init();
fnStats(&s.refCount, &s.staticCount, &s.eventCount);
+ if (staticInterface && s.refCount > 0)
+ --s.refCount;
return s;
}
@@ -287,13 +311,22 @@ private:
mutable QDotNetFunction<void, void *> fnFreeDelegateRef;
mutable QDotNetFunction<void, QDotNetRef> fnFreeObjectRef;
mutable QDotNetFunction<void, QString> fnFreeTypeRef;
- mutable QDotNetFunction<void *, QString> fnAddInterfaceProxy;
+ mutable QDotNetFunction<void *, QString, void *, void *> fnAddInterfaceProxy;
mutable QDotNetFunction<void, QDotNetRef, QString, qint32, QList<QDotNetParameter>,
void *, void *, void *> fnSetInterfaceMethod;
mutable QDotNetFunction<void, qint32 *, qint32 *, qint32 *> fnStats;
mutable QDotNetFunction<void *, QDotNetRef, QString> fnGetObject;
+ mutable QDotNetFunction<void> fnReset;
static inline const QString defaultDllName = QLatin1String("Qt.DotNet.Adapter.dll");
static inline const QString defaultAssemblyName = QLatin1String("Qt.DotNet.Adapter");
static inline const QString defaultTypeName = QLatin1String("Qt.DotNet.Adapter");
+
+ mutable void *staticInterface = nullptr;
+
+public:
+ inline static std::function<void *()> ctor_staticInterface = nullptr;
+ inline static std::function<void(void *)> dtor_staticInterface = nullptr;
+ inline static QDotNetFunction<void> gcCollect = nullptr;
+ inline static QDotNetFunction<void> gcWaitForPendingFinalizers = nullptr;
};
diff --git a/include/qdotnetarray.h b/include/qdotnetarray.h
index 3a0289b..9f97b5f 100644
--- a/include/qdotnetarray.h
+++ b/include/qdotnetarray.h
@@ -36,9 +36,9 @@ public:
QDotNetArray(qint32 length)
{
const QString elementTypeName = QDotNetTypeOf<T>::TypeName;
- const QDotNetType elementType = QDotNetType::find(elementTypeName);
+ const QDotNetType elementType = QDotNetType::typeOf(elementTypeName);
- QDotNetType arrayType = QDotNetType::find(QDotNetArray::FullyQualifiedTypeName);
+ QDotNetType arrayType = QDotNetType::typeOf(QDotNetArray::AssemblyQualifiedName);
auto ctor = constructor<QDotNetArray, qint32>();
*this = ctor(length);
}
diff --git a/include/qdotnetcallback.h b/include/qdotnetcallback.h
index 6efea1e..9f8c150 100644
--- a/include/qdotnetcallback.h
+++ b/include/qdotnetcallback.h
@@ -18,6 +18,19 @@
#include <functional>
+template<typename T>
+struct QDotNetCallbackArg : public QDotNetInbound<T> {};
+
+template<typename T>
+struct QDotNetCallbackReturn : public QDotNetOutbound<T> {};
+
+template<>
+struct QDotNetCallbackReturn<QString> : public QDotNetOutbound<QString>
+{
+ using SourceType = QString;
+ static inline const QDotNetParameter Parameter = QDotNetParameter::String;
+};
+
class QDotNetCallbackBase
{
protected:
@@ -30,18 +43,18 @@ template<typename TResult, typename... TArg>
class QDotNetCallback : public QDotNetCallbackBase
{
public:
- using ReturnType = typename QDotNetInbound<TResult>::TargetType;
- using FunctionType = std::function<ReturnType(
- typename QDotNetInbound<TArg>::TargetType... arg)>;
+ using FunctionType = std::function<TResult(void *, TArg... arg)>;
+ using CleanUpType = std::function<void(TResult *)>;
- using OutboundType = typename QDotNetOutbound<TResult>::OutboundType;
+ using OutboundType = typename QDotNetCallbackReturn<TResult>::OutboundType;
using Delegate = OutboundType(QDOTNETFUNCTION_CALLTYPE *)(
- QDotNetCallback *callback, quint64 key, typename QDotNetInbound<TArg>::InboundType...);
+ QDotNetCallback *callback, quint64 key,
+ void *data, typename QDotNetCallbackArg<TArg>::InboundType...);
using CleanUp = void(QDOTNETFUNCTION_CALLTYPE *)(QDotNetCallback *callback, quint64 key);
- QDotNetCallback(FunctionType function)
- : function(function)
+ QDotNetCallback(FunctionType fnCallback, CleanUpType fnCleanUp = nullptr)
+ : fnCallback(fnCallback), fnCleanUp(fnCleanUp)
{}
~QDotNetCallback() override = default;
@@ -59,64 +72,69 @@ public:
private:
struct Box
{
- ReturnType returnValue;
+ TResult returnValue;
+ Box(TResult &&ret) : returnValue(std::move(ret)) {}
};
QMap<quint64, Box *> boxes;
static OutboundType QDOTNETFUNCTION_CALLTYPE callbackDelegate(
- QDotNetCallback *callback, quint64 key, typename QDotNetInbound<TArg>::InboundType... arg)
+ QDotNetCallback *callback, quint64 key,
+ void *data, typename QDotNetCallbackArg<TArg>::InboundType... arg)
{
- Box *box = callback->boxes[key] = new Box
- {
- callback->function(QDotNetInbound<TArg>::convert(arg)...)
- };
- const auto result = QDotNetOutbound<TResult>::convert(box->returnValue);
- return result;
+ Box *box = callback->boxes[key] = new Box(
+ callback->fnCallback(data, QDotNetCallbackArg<TArg>::convert(arg)...));
+ return QDotNetCallbackReturn<TResult>::convert(box->returnValue);
}
static void QDOTNETFUNCTION_CALLTYPE callbackCleanUp(QDotNetCallback *callback, quint64 key)
{
- if (const Box *box = callback->boxes.take(key))
+ if (const Box *box = callback->boxes.take(key)) {
+ if (callback->fnCleanUp)
+ callback->fnCleanUp(const_cast<std::remove_const_t<TResult*>>(&(box->returnValue)));
delete box;
+ }
}
- FunctionType function = nullptr;
+ FunctionType fnCallback = nullptr;
+ CleanUpType fnCleanUp = nullptr;
};
template<typename... TArg>
class QDotNetCallback<void, TArg...> : public QDotNetCallbackBase
{
public:
- using FunctionType = std::function<void(typename QDotNetOutbound<TArg>::SourceType... arg)>;
+ using FunctionType = std::function<void(void *, TArg... arg)>;
+ using CleanUpType = nullptr_t;
+
+ using Delegate = void(QDOTNETFUNCTION_CALLTYPE *)(
+ QDotNetCallback *callback, quint64 key,
+ void *data, typename QDotNetCallbackArg<TArg>::InboundType...);
- QDotNetCallback(FunctionType function)
- : function(function)
+ using CleanUp = nullptr_t;
+
+ QDotNetCallback(FunctionType fnCallback, CleanUpType fnCleanUp = nullptr)
+ : fnCallback(fnCallback)
{}
~QDotNetCallback() override = default;
- using Delegate = void(QDOTNETFUNCTION_CALLTYPE *)(
- QDotNetCallback *callback, quint64 key, typename QDotNetInbound<TArg>::InboundType...);
static Delegate delegate()
{
return callbackDelegate;
}
- using CleanUp = void(QDOTNETFUNCTION_CALLTYPE *)(QDotNetCallback *callback, quint64 key);
static CleanUp cleanUp()
{
- return callbackCleanUp;
+ return nullptr;
}
private:
- static void QDOTNETFUNCTION_CALLTYPE callbackDelegate(QDotNetCallback *callback, quint64 key,
- typename QDotNetInbound<TArg>::InboundType... arg)
+ static void QDOTNETFUNCTION_CALLTYPE callbackDelegate(
+ QDotNetCallback *callback, quint64 key,
+ void *data, typename QDotNetCallbackArg<TArg>::InboundType... arg)
{
- callback->function(QDotNetInbound<TArg>::convert(arg)...);
+ callback->fnCallback(data, QDotNetCallbackArg<TArg>::convert(arg)...);
}
- static void QDOTNETFUNCTION_CALLTYPE callbackCleanUp(QDotNetCallback *callback, quint64 key)
- {}
-
- FunctionType function = nullptr;
+ FunctionType fnCallback = nullptr;
};
diff --git a/include/qdotnetdelegate.h b/include/qdotnetdelegate.h
new file mode 100644
index 0000000..25fc3a8
--- /dev/null
+++ b/include/qdotnetdelegate.h
@@ -0,0 +1,37 @@
+/***************************************************************************************************
+ Copyright (C) 2025 The Qt Company Ltd.
+ SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+***************************************************************************************************/
+
+#pragma once
+
+#include "qdotnetobject.h"
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wconversion"
+#endif
+#include <QString>
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+template<typename T, typename... TArg>
+class QDotNetDelegate : public QDotNetObject
+{
+public:
+ Q_DOTNET_OBJECT_INLINE(QDotNetDelegate, "System.Delegate");
+
+ T invoke(TArg... arg) const
+ {
+ return method("Invoke", fnInvoke).invoke(*this, arg...);
+ }
+
+ T operator()(TArg... arg) const
+ {
+ return invoke(arg...);
+ }
+
+private:
+ mutable QDotNetFunction<T, TArg...> fnInvoke;
+};
diff --git a/include/qdotnetevent.h b/include/qdotnetevent.h
index 11df0a1..00ea036 100644
--- a/include/qdotnetevent.h
+++ b/include/qdotnetevent.h
@@ -20,7 +20,8 @@
class QDotNetPropertyEvent : public QDotNetObject
{
public:
- Q_DOTNET_OBJECT_INLINE(QDotNetPropertyEvent, "System.ComponentModel.PropertyChangedEventArgs");
+ Q_DOTNET_OBJECT_INLINE(QDotNetPropertyEvent,
+ "System.ComponentModel.PropertyChangedEventArgs, System.ObjectModel");
QString propertyName() const
{
diff --git a/include/qdotnethost.h b/include/qdotnethost.h
index c2fe298..05b0922 100644
--- a/include/qdotnethost.h
+++ b/include/qdotnethost.h
@@ -35,7 +35,7 @@ public:
unload();
}
- bool load(const QString& runtimeConfig = defaultRuntimeConfig, const QString &runtimePath = {})
+ bool load(const QString &runtimeConfig = defaultRuntimeConfig, const QString &runtimePath = {})
{
if (isLoaded())
return true;
@@ -48,6 +48,57 @@ public:
return true;
}
+ bool appMain(const QString &appHostPath, const QString &appLibPath)
+ {
+ if (isLoaded())
+ return false;
+
+ if (!loadRuntime({}))
+ return false;
+ const char_t *host_path = STR(appHostPath);
+ const char_t *app_path = STR(appLibPath);
+ const char_t *dotnet_root = (char_t *)L"C:\\Program Files\\dotnet\\";
+
+ int argc = 1;
+ const char_t *argv[] = { host_path, nullptr };
+
+ return fnMainStartup(argc, argv, host_path, dotnet_root, app_path) == 0;
+ }
+
+ bool loadApp(const QString &appPath, const QStringList &args = {}, const QString &runtimePath = {})
+ {
+ if (isLoaded())
+ return false;
+
+ if (!loadRuntime(runtimePath))
+ return false;
+
+ int argc = 1;
+ const char_t *argv[] = { STR(appPath), nullptr };
+
+ auto result = fnInitApp(argc, argv, nullptr, &hostContext);
+ if (HOSTFN_FAILED(result) || hostContext == nullptr) {
+ qCritical() << "Error calling function: hostfxr_initialize_for_dotnet_command_line";
+ unloadRuntime();
+ return false;
+ }
+
+ setRuntimeProperty("STARTUP_HOOKS",
+ QDir(QCoreApplication::applicationDirPath()).filePath("Qt.DotNet.Adapter.dll"));
+
+ setRuntimeProperty("QT_DOTNET_RESOLVE_FN", QString("%1")
+ .arg((qulonglong)(&fnLoadAssemblyAndGetFunctionPointer), 16, 16, QChar('0')));
+
+ return true;
+ }
+
+ int runApp()
+ {
+ if (!isLoaded() || fnLoadAssemblyAndGetFunctionPointer != nullptr)
+ return false;
+ return fnRunApp(hostContext);
+ }
+
void unload()
{
if (!isLoaded())
@@ -61,6 +112,11 @@ public:
return (hostContext != nullptr);
}
+ bool isReady() const
+ {
+ return (fnLoadAssemblyAndGetFunctionPointer != nullptr);
+ }
+
bool resolveFunction(QDotNetFunction<quint32, void *, qint32> &outFunc,
const QString &assemblyPath, const QString &typeName, const QString &methodName)
{
@@ -172,51 +228,49 @@ private:
}
const QString dotNetInfo(procDotNetInfo.readAllStandardOutput());
- QString runtimeDirPath = {};
- QString hostVersion = {};
- QVersionNumber maxVersion;
+ QVersionNumber selectedVersion = {};
+ QString selectedRuntimePath = {};
const QRegularExpression dotNetInfoParser(regexParseDotNetInfo,
QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption);
for (const auto &match : dotNetInfoParser.globalMatch(dotNetInfo)) {
- const auto version = QVersionNumber::fromString(match.captured("version"));
- if (version > maxVersion) {
- maxVersion = version;
- hostVersion = match.captured("version");
- runtimeDirPath = match.captured("path");
- }
- }
-
- if (runtimeDirPath.isEmpty()) {
- qCritical() << "Error parsing dotnet info";
- return {};
- }
- QDir runtimeDir(runtimeDirPath);
- if (!runtimeDir.exists()) {
- qCritical() << "Error dotnet runtime directory not found";
- return {};
- }
-
- runtimeDir.cd(QString("../../host/fxr/%1").arg(hostVersion));
- if (!runtimeDir.exists()) {
- qCritical() << "Error dotnet host fxr directory not found";
- return {};
- }
+ const auto hostVersion = match.captured("version");
+ const auto version = QVersionNumber::fromString(hostVersion);
+ if (version <= selectedVersion)
+ continue;
+
+ const auto runtimeDirPath = match.captured("path");
+ if (runtimeDirPath.isEmpty())
+ continue;
+ QDir runtimeDir(runtimeDirPath);
+ if (!runtimeDir.exists())
+ continue;
+ runtimeDir.cd(QString("../../host/fxr/%1").arg(hostVersion));
+ if (!runtimeDir.exists())
+ continue;
#ifdef Q_OS_WINDOWS
- QString runtimePath = runtimeDir.absoluteFilePath("hostfxr.dll");
+ const auto runtimePath = runtimeDir.absoluteFilePath("hostfxr.dll");
#else
- QString runtimePath = runtimeDir.absoluteFilePath("libhostfxr.so");
+ const auto runtimePath = runtimeDir.absoluteFilePath("libhostfxr.so");
#endif
- if (!QFile::exists(runtimePath)) {
- qCritical() << "Error dotnet host fxr dll not found";
+ if (!QFile::exists(runtimePath))
+ continue;
+
+ selectedVersion = version;
+ selectedRuntimePath = runtimePath;
+ }
+
+ if (selectedVersion.isNull()) {
+ qCritical() << "Error locating runtime host library.";
return {};
}
- return runtimePath;
+
+ return selectedRuntimePath;
}
bool loadRuntime(const QString & runtimePath)
{
- if (fnInitHost != nullptr)
+ if (fnCloseHost != nullptr)
return true;
if (!runtimePath.isEmpty()) {
@@ -235,45 +289,53 @@ private:
return false;
}
- fnInitHost = GET_FN(runtime, hostfxr_initialize_for_runtime_config_fn);
- if (!fnInitHost) {
- qCritical() << "Error loading function: hostfxr_initialize_for_runtime_config";
+ if (!(fnMainStartup = GET_FN(runtime, hostfxr_main_startupinfo_fn))) {
+ qCritical() << "Error loading function: hostfxr_main_startupinfo";
return false;
}
- fnGetRuntimeDelegate = GET_FN(runtime, hostfxr_get_runtime_delegate_fn);
- if (!fnGetRuntimeDelegate) {
- qCritical() << "Error loading function: hostfxr_get_runtime_delegate";
+ if (!(fnSetErrorWriter = GET_FN(runtime, hostfxr_set_error_writer_fn))) {
+ qCritical() << "Error loading function: hostfxr_set_error_writer";
return false;
}
- fnCloseHost = GET_FN(runtime, hostfxr_close_fn);
- if (!fnCloseHost) {
- qCritical() << "Error loading function: hostfxr_close";
+ if (!(fnInitApp = GET_FN(runtime, hostfxr_initialize_for_dotnet_command_line_fn))) {
+ qCritical() << "Error loading function: hostfxr_initialize_for_dotnet_command_line";
return false;
}
- fnSetErrorWriter = GET_FN(runtime, hostfxr_set_error_writer_fn);
- if (!fnSetErrorWriter) {
- qCritical() << "Error loading function: hostfxr_set_error_writer";
+ if (!(fnInitHost = GET_FN(runtime, hostfxr_initialize_for_runtime_config_fn))) {
+ qCritical() << "Error loading function: hostfxr_initialize_for_runtime_config";
+ return false;
+ }
+
+ if (!(fnRuntimeProperty = GET_FN(runtime, hostfxr_get_runtime_property_value_fn))) {
+ qCritical() << "Error loading function: hostfxr_get_runtime_property_value_fn";
+ return false;
+ }
+
+ if (!(fnSetRuntimeProperty = GET_FN(runtime, hostfxr_set_runtime_property_value_fn))) {
+ qCritical() << "Error loading function: hostfxr_set_runtime_property_value_fn";
return false;
}
- fnAllRuntimeProperties = GET_FN(runtime, hostfxr_get_runtime_properties_fn);
- if (!fnAllRuntimeProperties) {
+ if (!(fnAllRuntimeProperties = GET_FN(runtime, hostfxr_get_runtime_properties_fn))) {
qCritical() << "Error loading function: hostfxr_get_runtime_properties_fn";
return false;
}
- fnRuntimeProperty = GET_FN(runtime, hostfxr_get_runtime_property_value_fn);
- if (!fnRuntimeProperty) {
- qCritical() << "Error loading function: hostfxr_get_runtime_property_value_fn";
+ if (!(fnRunApp = GET_FN(runtime, hostfxr_run_app_fn))) {
+ qCritical() << "Error loading function: hostfxr_run_app";
return false;
}
- fnSetRuntimeProperty = GET_FN(runtime, hostfxr_set_runtime_property_value_fn);
- if (!fnSetRuntimeProperty) {
- qCritical() << "Error loading function: hostfxr_set_runtime_property_value_fn";
+ if (!(fnGetRuntimeDelegate = GET_FN(runtime, hostfxr_get_runtime_delegate_fn))) {
+ qCritical() << "Error loading function: hostfxr_get_runtime_delegate";
+ return false;
+ }
+
+ if (!(fnCloseHost = GET_FN(runtime, hostfxr_close_fn))) {
+ qCritical() << "Error loading function: hostfxr_close";
return false;
}
@@ -283,17 +345,26 @@ private:
void unloadRuntime()
{
- runtime.unload();
+ fnSetErrorWriter = nullptr;
+ fnInitApp = nullptr;
fnInitHost = nullptr;
- fnGetRuntimeDelegate = nullptr;
- fnCloseHost = nullptr;
- fnAllRuntimeProperties = nullptr;
fnRuntimeProperty = nullptr;
fnSetRuntimeProperty = nullptr;
+ fnAllRuntimeProperties = nullptr;
+ fnRunApp = nullptr;
+ fnGetRuntimeDelegate = nullptr;
+ fnCloseHost = nullptr;
+ fnLoadAssemblyAndGetFunctionPointer = nullptr;
+ fnLoadAssembly = nullptr;
+ fnGetFunctionPointer = nullptr;
+ runtime.unload();
}
bool init(const QString &runtimeConfig)
{
+ if (fnLoadAssemblyAndGetFunctionPointer)
+ return true;
+
if (fnInitHost == nullptr)
return false;
@@ -365,11 +436,11 @@ private:
static inline const QString defaultRuntimeConfig = QStringLiteral(R"[json](
{
"runtimeOptions": {
- "tfm": "net6.0",
+ "tfm": "net8.0",
"rollForward": "LatestMinor",
"framework": {
"name": "Microsoft.NETCore.App",
- "version": "6.0.0"
+ "version": "8.0.0"
}
}
}
@@ -379,16 +450,24 @@ private:
\bMicrosoft\.NETCore\.App[^0-9]*(?<version>[0-9\.]+)[^\[]*\[(?<path>[^\]]+)\]
)[regex]").remove('\r').remove('\n');
+ static inline const QString regexParseDotNetRoot = QStringLiteral(R"[regex](
+^(?:(?![\\\/]host[\\\/]).)*[\\\/]
+)[regex]").remove('\r').remove('\n');
QLibrary runtime;
- hostfxr_initialize_for_runtime_config_fn fnInitHost = nullptr;
- hostfxr_get_runtime_delegate_fn fnGetRuntimeDelegate = nullptr;
- hostfxr_close_fn fnCloseHost = nullptr;
+ hostfxr_main_startupinfo_fn fnMainStartup = nullptr;
hostfxr_set_error_writer_fn fnSetErrorWriter = nullptr;
- hostfxr_get_runtime_properties_fn fnAllRuntimeProperties = nullptr;
+ hostfxr_initialize_for_dotnet_command_line_fn fnInitApp = nullptr;
+ hostfxr_initialize_for_runtime_config_fn fnInitHost = nullptr;
hostfxr_get_runtime_property_value_fn fnRuntimeProperty = nullptr;
hostfxr_set_runtime_property_value_fn fnSetRuntimeProperty = nullptr;
+ hostfxr_get_runtime_properties_fn fnAllRuntimeProperties = nullptr;
+ hostfxr_run_app_fn fnRunApp = nullptr;
+ hostfxr_get_runtime_delegate_fn fnGetRuntimeDelegate = nullptr;
+ hostfxr_close_fn fnCloseHost = nullptr;
hostfxr_handle hostContext = nullptr;
load_assembly_and_get_function_pointer_fn fnLoadAssemblyAndGetFunctionPointer = nullptr;
+ load_assembly_fn fnLoadAssembly = nullptr;
+ get_function_pointer_fn fnGetFunctionPointer = nullptr;
};
diff --git a/include/qdotnethostfxr.h b/include/qdotnethostfxr.h
index e5e1d0c..dc57ce0 100644
--- a/include/qdotnethostfxr.h
+++ b/include/qdotnethostfxr.h
@@ -116,6 +116,13 @@ using get_hostfxr_path_fn = quint32(NETHOST_CALLTYPE *)(
# define HOSTFXR_CALLTYPE
#endif
+using hostfxr_main_startupinfo_fn = int(HOSTFXR_CALLTYPE *)(
+ const int argc,
+ const char_t **argv,
+ const char_t *host_path,
+ const char_t *dotnet_root,
+ const char_t *app_path);
+
enum hostfxr_delegate_type
{
hdt_com_activation,
@@ -124,7 +131,9 @@ enum hostfxr_delegate_type
hdt_com_register,
hdt_com_unregister,
hdt_load_assembly_and_get_function_pointer,
- hdt_get_function_pointer
+ hdt_get_function_pointer,
+ hdt_load_assembly,
+ hdt_load_assembly_bytes
};
using hostfxr_error_writer_fn = void(HOSTFXR_CALLTYPE *)(const char_t *message);
@@ -140,6 +149,13 @@ struct hostfxr_initialize_parameters
const char_t *dotnet_root;
};
+using hostfxr_initialize_for_dotnet_command_line_fn = int(HOSTFXR_CALLTYPE *)(
+ int argc,
+ const char_t *argv[],
+ const hostfxr_initialize_parameters *parameters,
+ /*out*/ hostfxr_handle *host_context_handle
+);
+
using hostfxr_initialize_for_runtime_config_fn = quint32(HOSTFXR_CALLTYPE *)(
const char_t *runtime_config_path,
const hostfxr_initialize_parameters *parameters,
@@ -161,6 +177,8 @@ using hostfxr_get_runtime_properties_fn = quint32(HOSTFXR_CALLTYPE *)(
/*out*/ const char_t **keys,
/*out*/ const char_t **values);
+using hostfxr_run_app_fn = int (HOSTFXR_CALLTYPE *)(const hostfxr_handle host_context_handle);
+
using hostfxr_get_runtime_delegate_fn = quint32(HOSTFXR_CALLTYPE *)(
hostfxr_handle host_context_handle,
hostfxr_delegate_type type,
@@ -168,7 +186,6 @@ using hostfxr_get_runtime_delegate_fn = quint32(HOSTFXR_CALLTYPE *)(
using hostfxr_close_fn = quint32(HOSTFXR_CALLTYPE *)(hostfxr_handle host_context_handle);
-
/*
adapted from:
https://github.com/dotnet/runtime/blob/main/src/native/corehost/coreclr_delegates.h
@@ -179,25 +196,26 @@ using hostfxr_close_fn = quint32(HOSTFXR_CALLTYPE *)(hostfxr_handle host_context
# define CORECLR_DELEGATE_CALLTYPE
#endif
-using component_entry_point_fn = quint32(CORECLR_DELEGATE_CALLTYPE *)(
- void *arg, qint32 arg_size_in_bytes);
-
using load_assembly_and_get_function_pointer_fn = quint32(CORECLR_DELEGATE_CALLTYPE *)(
const char_t *assembly_path ,
const char_t *type_name ,
const char_t *method_name ,
const char_t *delegate_type_name,
- void *reserved,
+ nullptr_t reserved,
/*out*/ void **delegate );
using get_function_pointer_fn = quint32(CORECLR_DELEGATE_CALLTYPE *)(
const char_t *type_name,
const char_t *method_name,
const char_t *delegate_type_name,
- void *load_context,
- void *reserved,
+ nullptr_t load_context,
+ nullptr_t reserved,
/*out*/ void **delegate);
+using load_assembly_fn = int (CORECLR_DELEGATE_CALLTYPE *)(
+ const char_t *assembly_path,
+ nullptr_t load_context,
+ nullptr_t reserved);
/*
adapted from:
diff --git a/include/qdotnetinterface.h b/include/qdotnetinterface.h
index 4dae61c..c6850e3 100644
--- a/include/qdotnetinterface.h
+++ b/include/qdotnetinterface.h
@@ -21,44 +21,71 @@
class QDotNetInterface : public QDotNetRef
{
public:
- QDotNetInterface(const QString &interfaceName)
- : QDotNetRef(adapter().addInterfaceProxy(interfaceName))
+ QDotNetInterface(const QString &interfaceName, void *data = nullptr, void *cleanUp = nullptr)
+ : QDotNetRef(adapter().addInterfaceProxy(interfaceName, data, cleanUp))
{}
- template<typename TResult, typename... TArg>
- void setCallback(const QString &methodName, const QList<QDotNetParameter> &params,
- typename QDotNetCallback<TResult, TArg...>::FunctionType function)
+ QDotNetInterface(const void *objectRef = nullptr)
+ : QDotNetRef(objectRef)
+ {}
+
+ QDotNetInterface(const QDotNetInterface &cpySrc)
+ : QDotNetRef(cpySrc)
+ {}
+
+ QDotNetInterface &operator =(const QDotNetInterface &cpySrc)
{
- auto *callback = new QDotNetCallback<TResult, TArg...>(function);
- callbacks.append(callback);
+ QDotNetRef::operator=(cpySrc);
+ return *this;
+ }
- QList<QDotNetParameter> modifiedParams
- {
- params[0],
- UnmanagedType::SysInt,
- UnmanagedType::U8
- };
- for (qsizetype i = 1; i < params.size(); ++i)
- modifiedParams.append(params[i]);
+ QDotNetInterface(QDotNetInterface &&movSrc) noexcept
+ : QDotNetRef(std::move(movSrc))
+ {}
- adapter().setInterfaceMethod(*this, methodName, modifiedParams,
- reinterpret_cast<void *>(callback->delegate()),
- reinterpret_cast<void *>(callback->cleanUp()), callback);
+ QDotNetInterface &operator=(QDotNetInterface &&movSrc) noexcept
+ {
+ QDotNetRef::operator=(std::move(movSrc));
+ return *this;
+ }
+
+ template<typename T>
+ T *dataAs()
+ {
+ if (!fnDataPtr.isValid()) {
+ const QList<QDotNetParameter> parameters
+ {
+ QDotNetInbound<void *>::Parameter
+ };
+ fnDataPtr = adapter().resolveInstanceMethod(*this, "get_Data", parameters);
+ }
+ return reinterpret_cast<T *>(fnDataPtr());
+ }
+
+ virtual ~QDotNetInterface() override
+ {
+ if (!isValid())
+ return;
+ for (const QDotNetCallbackBase *callback : callbacks)
+ delete callback;
+ callbacks.clear();
}
template<typename TResult, typename... TArg>
void setCallback(const QString &methodName,
- typename QDotNetCallback<TResult, TArg...>::FunctionType function)
+ typename QDotNetCallback<TResult, TArg...>::FunctionType function,
+ typename QDotNetCallback<TResult, TArg...>::CleanUpType cleanUp = nullptr)
{
- auto *callback = new QDotNetCallback<TResult, TArg...>(function);
+ auto *callback = new QDotNetCallback<TResult, TArg...>(function, cleanUp);
callbacks.append(callback);
const QList<QDotNetParameter> parameters
{
- QDotNetInbound<TResult>::Parameter,
+ QDotNetCallbackReturn<TResult>::Parameter,
UnmanagedType::SysInt,
UnmanagedType::U8,
- QDotNetInbound<TArg>::Parameter...
+ UnmanagedType::SysInt,
+ QDotNetCallbackArg<TArg>::Parameter...
};
adapter().setInterfaceMethod(
@@ -66,20 +93,44 @@ public:
callback->delegate(), callback->cleanUp(), callback);
}
- ~QDotNetInterface() override
- {
- for (const QDotNetCallbackBase *callback : callbacks)
- delete callback;
- callbacks.clear();
- }
-
private:
QList<QDotNetCallbackBase *> callbacks;
+ QDotNetFunction<void *> fnDataPtr = nullptr;
};
template<typename T>
struct QDotNetTypeOf<T, std::enable_if_t<std::is_base_of_v<QDotNetInterface, T>>>
{
- static inline const QString TypeName = T::FullyQualifiedTypeName;
+ static inline const QString TypeName = T::AssemblyQualifiedName;
static inline UnmanagedType MarshalAs = UnmanagedType::ObjectRef;
};
+
+template<typename T>
+struct QDotNetNativeInterface : public QDotNetInterface
+{
+ QDotNetNativeInterface(const void *objectRef = nullptr)
+ : QDotNetInterface(objectRef)
+ {
+ }
+
+ QDotNetNativeInterface(const QString &interfaceName, T *data, bool doCleanUp = true)
+ : QDotNetInterface(interfaceName, data, doCleanUp ? cleanUp : nullptr)
+ {
+ }
+
+ T *data()
+ {
+ return dataAs<T>();
+ }
+
+ operator T&()
+ {
+ return *data();
+ }
+
+ static void QDOTNETFUNCTION_CALLTYPE cleanUp(void *data)
+ {
+ if (data)
+ delete reinterpret_cast<T *>(data);
+ }
+};
diff --git a/include/qdotnetobject.h b/include/qdotnetobject.h
index 34dbc3c..5657c6f 100644
--- a/include/qdotnetobject.h
+++ b/include/qdotnetobject.h
@@ -17,6 +17,8 @@
# pragma GCC diagnostic pop
#endif
+struct QDotNetEventHandler;
+
class QDotNetObject : public QDotNetRef
{
private:
@@ -37,7 +39,7 @@ private:
// Fully qualified .NET class name
#define Q_DOTNET_OBJECT_TYPE(T,type_name)\
- static inline const QString &FullyQualifiedTypeName = QString(type_name)
+ static inline const QString &AssemblyQualifiedName = QString(type_name)
// All required declarations
#define Q_DOTNET_OBJECT(T,type_name)\
@@ -125,7 +127,7 @@ private:
#define Q_DOTNET_OBJECT_INIT(...) , __VA_ARGS__
public:
- static inline const QString &FullyQualifiedTypeName = QStringLiteral("System.Object");
+ static inline const QString &AssemblyQualifiedName = QStringLiteral("System.Object");
QDotNetObject(const void *objectRef = nullptr)
: QDotNetRef(objectRef)
@@ -151,6 +153,8 @@ public:
return *this;
}
+ virtual ~QDotNetObject() override = default;
+
const QDotNetType &type() const
{
if (!fnGetType.isValid()) {
@@ -160,16 +164,6 @@ public:
return objType;
}
- QString toString() const
- {
- return method("ToString", fnToString).invoke(*this);
- }
-
- bool equals(const QDotNetRef &obj) const
- {
- return method("Equals", fnEquals).invoke(*this, obj);
- }
-
template<typename TResult, typename ...TArg>
QDotNetFunction<TResult, TArg...> method(const QString &methodName) const
{
@@ -243,19 +237,12 @@ public:
return QDotNetType::constructor(typeName, ctor);
}
- struct IEventHandler
- {
- virtual ~IEventHandler() = default;
- virtual void handleEvent(const QString &eventName, QDotNetObject &eventSource,
- QDotNetObject &eventArgs) = 0;
- };
-
- void subscribeEvent(const QString &eventName, IEventHandler *eventHandler)
+ void subscribe(const QString &eventName, QDotNetEventHandler *eventHandler)
{
adapter().addEventHandler(*this, eventName, eventHandler, eventCallback);
}
- void unsubscribeEvent(const QString &eventName, IEventHandler *eventHandler)
+ void unsubscribe(const QString &eventName, QDotNetEventHandler *eventHandler)
{
adapter().removeEventHandler(*this, eventName, eventHandler);
}
@@ -281,31 +268,24 @@ protected:
template<typename T, typename ...TArg>
static QDotNetFunction<T, TArg...> constructor()
{
- return QDotNetType::constructor<T, TArg...>(T::FullyQualifiedTypeName);
+ return QDotNetType::constructor<T, TArg...>(T::AssemblyQualifiedName);
}
template<typename T, typename ...TArg>
static QDotNetFunction<T, TArg...> &constructor(QDotNetFunction<T, TArg...> &ctor)
{
- return QDotNetType::constructor(T::FullyQualifiedTypeName, ctor);
+ return QDotNetType::constructor(T::AssemblyQualifiedName, ctor);
}
template<typename T, typename ...TArg>
static QDotNetSafeMethod<T, TArg...> &constructor(QDotNetSafeMethod<T, TArg...> &ctor)
{
- return QDotNetType::constructor(T::FullyQualifiedTypeName, ctor);
+ return QDotNetType::constructor(T::AssemblyQualifiedName, ctor);
}
private:
- static void QDOTNETFUNCTION_CALLTYPE eventCallback(void *context, void *eventNameChars,
- void *eventSourceRef, void *eventArgsRef)
- {
- auto *receiver = static_cast<IEventHandler *>(context);
- const QString eventName(static_cast<const QChar *>(eventNameChars));
- QDotNetObject eventSource(eventSourceRef);
- QDotNetObject eventArgs(eventArgsRef);
- receiver->handleEvent(eventName, eventSource, eventArgs);
- }
+ static inline void QDOTNETFUNCTION_CALLTYPE eventCallback(void *context, void *eventNameChars,
+ void *eventSourceRef, void *eventArgsRef);
mutable QDotNetFunction<QDotNetType> fnGetType;
mutable QDotNetType objType = nullptr;
@@ -313,9 +293,26 @@ private:
mutable QDotNetFunction<bool, QDotNetRef> fnEquals;
};
+struct QDotNetEventHandler
+{
+ virtual ~QDotNetEventHandler() = default;
+ virtual void handleEvent(const QString &eventName, QDotNetObject &eventSource,
+ QDotNetObject &eventArgs) = 0;
+};
+
+inline void QDOTNETFUNCTION_CALLTYPE QDotNetObject::eventCallback(void *context, void *eventNameChars,
+ void *eventSourceRef, void *eventArgsRef)
+{
+ auto *receiver = static_cast<QDotNetEventHandler *>(context);
+ const QString eventName(static_cast<const QChar *>(eventNameChars));
+ QDotNetObject eventSource(eventSourceRef);
+ QDotNetObject eventArgs(eventArgsRef);
+ receiver->handleEvent(eventName, eventSource, eventArgs);
+}
+
template<typename T>
struct QDotNetTypeOf<T, std::enable_if_t<std::is_base_of_v<QDotNetObject, T>>>
{
- static inline const QString TypeName = T::FullyQualifiedTypeName;
+ static inline const QString TypeName = T::AssemblyQualifiedName;
static inline UnmanagedType MarshalAs = UnmanagedType::ObjectRef;
};
diff --git a/include/qdotnetref.h b/include/qdotnetref.h
index fff2e06..06ce02a 100644
--- a/include/qdotnetref.h
+++ b/include/qdotnetref.h
@@ -10,7 +10,7 @@
class QDotNetRef
{
public:
- static inline const QString &FullyQualifiedTypeName = QStringLiteral("System.Object");
+ static inline const QString &AssemblyQualifiedName = QStringLiteral("System.Object");
const void *gcHandle() const { return objectRef; }
bool isValid() const { return gcHandle() != nullptr; }
@@ -59,6 +59,32 @@ public:
class Null
{};
+ QString toString() const
+ {
+ if (!fnToString.isValid()) {
+ const QList<QDotNetParameter> parameters
+ {
+ QDotNetInbound<QString>::Parameter
+ };
+ fnToString = adapter().resolveInstanceMethod(*this, "ToString", parameters);
+ }
+ return fnToString();
+ }
+
+ bool equals(const QDotNetRef &obj) const
+ {
+ if (!fnEquals.isValid()) {
+ const QList<QDotNetParameter> parameters
+ {
+ QDotNetInbound<bool>::Parameter,
+ QDotNetOutbound<QDotNetRef>::Parameter
+ };
+ fnEquals = adapter().resolveInstanceMethod(*this, "Equals", parameters);
+ }
+ return fnEquals(obj);
+ }
+
+
protected:
static QDotNetAdapter &adapter() { return QDotNetAdapter::instance(); }
@@ -93,6 +119,9 @@ private:
}
const void *objectRef = nullptr;
+
+ mutable QDotNetFunction<QString> fnToString = nullptr;
+ mutable QDotNetFunction<bool, QDotNetRef> fnEquals = nullptr;
};
template<typename T>
diff --git a/include/qdotnetstatic.h b/include/qdotnetstatic.h
new file mode 100644
index 0000000..7b07147
--- /dev/null
+++ b/include/qdotnetstatic.h
@@ -0,0 +1,53 @@
+/***************************************************************************************************
+ Copyright (C) 2024 The Qt Company Ltd.
+ SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+***************************************************************************************************/
+
+#pragma once
+
+#include "qdotnetinterface.h"
+#include "iqmodelindex.h"
+#include "iqvariant.h"
+#include "qdotnetabstractlistmodel.h"
+
+#include <functional>
+
+class QDotNetStatic : public QDotNetInterface
+{
+public:
+ static inline const QString &AssemblyQualifiedName =
+ QStringLiteral("Qt.DotNet.Adapter+IStatic, Qt.DotNet.Adapter");
+
+ QDotNetStatic(const void *objectRef) : QDotNetInterface(objectRef) {}
+
+ QDotNetStatic() : QDotNetInterface(AssemblyQualifiedName, nullptr)
+ {
+ IQVariant::staticInit(this);
+ IQModelIndex::staticInit(this);
+ QDotNetAbstractListModel::staticInit(this);
+ }
+};
+
+inline static bool ctor_static = std::invoke([]()
+ {
+ QDotNetAdapter::ctor_staticInterface = []()
+ {
+ auto *staticQVariant = new QDotNetStatic();
+ auto setStatic = QDotNetType::staticMethod<void, QDotNetStatic>(
+ "Qt.DotNet.Adapter, Qt.DotNet.Adapter", "set_Static");
+ setStatic(*staticQVariant);
+ return staticQVariant;
+ };
+ return true;
+ });
+
+inline static bool dtor_static = std::invoke([]()
+ {
+ QDotNetAdapter::dtor_staticInterface = [](void *that)
+ {
+ QtDotNet::call<void, QDotNetStatic>(
+ "Qt.DotNet.Adapter, Qt.DotNet.Adapter", "set_Static", nullptr);
+ delete reinterpret_cast<QDotNetStatic *>(that);
+ };
+ return true;
+ });
diff --git a/include/qdotnettype.h b/include/qdotnettype.h
index 4ab99bf..dc3bb90 100644
--- a/include/qdotnettype.h
+++ b/include/qdotnettype.h
@@ -19,7 +19,7 @@
class QDotNetType : public QDotNetRef
{
public:
- static inline const QString &FullyQualifiedTypeName = QStringLiteral("System.Type");
+ static inline const QString &AssemblyQualifiedName = QStringLiteral("System.Type");
QDotNetType(const void *typeRef = nullptr)
: QDotNetRef(typeRef)
@@ -45,6 +45,18 @@ public:
return *this;
}
+ QString assemblyQualifiedName() const
+ {
+ if (!isValid())
+ return QStringLiteral("");
+ if (!fnAssemblyQualifiedName.isValid()) {
+ fnAssemblyQualifiedName = adapter().resolveInstanceMethod(*this,
+ "get_AssemblyQualifiedName", { UnmanagedType::LPWStr });
+ strFullName = fnAssemblyQualifiedName();
+ }
+ return strFullName;
+ }
+
QString fullName() const
{
if (!isValid())
@@ -57,16 +69,16 @@ public:
return strFullName;
}
- static QDotNetType find(const QString &typeName)
+ static QDotNetType typeOf(const QString &typeName)
{
QDotNetFunction<QDotNetType, QString> fnGetType;
- return staticMethod(FullyQualifiedTypeName, "GetType", fnGetType).invoke(nullptr, typeName);
+ return staticMethod(AssemblyQualifiedName, "GetType", fnGetType).invoke(nullptr, typeName);
}
template<typename T>
- static QDotNetType find()
+ static QDotNetType typeOf()
{
- return find(T::FullyQualifiedTypeName);
+ return typeOf(T::AssemblyQualifiedName);
}
template<typename TResult, typename ...TArg>
@@ -102,7 +114,7 @@ public:
template<typename TResult, typename ...TArg>
QDotNetFunction<TResult, TArg...> staticMethod(const QString &methodName) const
{
- return staticMethod<TResult, TArg...>(fullName(), methodName);
+ return staticMethod<TResult, TArg...>(assemblyQualifiedName(), methodName);
}
template<typename TResult, typename ...TArg>
@@ -155,24 +167,24 @@ public:
template<typename T, typename ...TArg>
QDotNetFunction<T, TArg...> constructor() const
{
- return constructor<T, TArg...>(fullName());
+ return constructor<T, TArg...>(assemblyQualifiedName());
}
template<typename T, typename ...TArg>
QDotNetFunction<T, TArg...> &constructor(QDotNetFunction<T, TArg...> &ctor) const
{
- return constructor(fullName(), ctor);
+ return constructor(assemblyQualifiedName(), ctor);
}
template<typename T, typename ...TArg>
QDotNetFunction<T, TArg...> &constructor(QDotNetSafeMethod<T, TArg...> &ctor) const
{
- return constructor(fullName(), ctor);
+ return constructor(assemblyQualifiedName(), ctor);
}
void freeTypeRef()
{
- freeTypeRef(fullName());
+ freeTypeRef(assemblyQualifiedName());
}
static void freeTypeRef(const QString &typeName)
@@ -183,12 +195,53 @@ public:
template<typename T>
static void freeTypeRef()
{
- freeTypeRef(T::FullyQualifiedTypeName);
+ freeTypeRef(T::AssemblyQualifiedName);
+ }
+
+ bool isAssignableFrom(QDotNetType c) const
+ {
+ if (!c.isValid())
+ return false;
+ if (!fnIsAssignableFrom.isValid()) {
+ fnIsAssignableFrom = adapter().resolveInstanceMethod(*this, "IsAssignableFrom",
+ { UnmanagedType::Bool, QStringLiteral("System.Type") });
+ if (!fnIsAssignableFrom.isValid())
+ return false;
+ }
+ return fnIsAssignableFrom(c);
+ }
+
+ template<typename T>
+ bool isAssignableFrom() const
+ {
+ return isAssignableFrom(typeOf<T>());
+ }
+
+ bool isAssignableTo(QDotNetType c) const
+ {
+ if (!c.isValid())
+ return false;
+ if (!fnIsAssignableTo.isValid()) {
+ fnIsAssignableTo = adapter().resolveInstanceMethod(*this, "IsAssignableTo",
+ { UnmanagedType::Bool, QStringLiteral("System.Type") });
+ if (!fnIsAssignableTo.isValid())
+ return false;
+ }
+ return fnIsAssignableTo(c);
+ }
+
+ template<typename T>
+ bool isAssignableTo() const
+ {
+ return isAssignableTo(typeOf<T>());
}
private:
+ mutable QDotNetFunction<QString> fnAssemblyQualifiedName;
mutable QDotNetFunction<QString> fnFullName;
mutable QString strFullName;
+ mutable QDotNetFunction<bool, QDotNetRef> fnIsAssignableFrom;
+ mutable QDotNetFunction<bool, QDotNetRef> fnIsAssignableTo;
};
namespace QtDotNet