mirror of
https://github.com/qmlnet/qmlnet.git
synced 2026-05-21 06:45:32 -06:00
parent
182232703b
commit
820da15d20
23 changed files with 720 additions and 33 deletions
6
samples/hosting/.gitignore
vendored
Normal file
6
samples/hosting/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
build-*/
|
||||||
|
*.pro.user
|
||||||
|
net-output/
|
||||||
|
net/.idea/
|
||||||
|
net/obj/
|
||||||
|
net/.vs/
|
||||||
13
samples/hosting/native/NativeHost.pro
Normal file
13
samples/hosting/native/NativeHost.pro
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
QT += quick
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
main.cpp
|
||||||
|
|
||||||
|
RESOURCES += qml.qrc
|
||||||
|
|
||||||
|
DEFINES += "NET_ROOT=\"\\\"$$PWD/../net-output\\\"\""
|
||||||
|
|
||||||
|
include (../../../src/native/QmlNet/Hosting.pri)
|
||||||
18
samples/hosting/native/Page1Form.ui.qml
Normal file
18
samples/hosting/native/Page1Form.ui.qml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
|
||||||
|
Page {
|
||||||
|
width: 600
|
||||||
|
height: 400
|
||||||
|
|
||||||
|
header: Label {
|
||||||
|
text: qsTr("Page 1")
|
||||||
|
font.pixelSize: Qt.application.font.pixelSize * 2
|
||||||
|
padding: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("You are on Page 1.")
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
18
samples/hosting/native/Page2Form.ui.qml
Normal file
18
samples/hosting/native/Page2Form.ui.qml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
|
||||||
|
Page {
|
||||||
|
width: 600
|
||||||
|
height: 400
|
||||||
|
|
||||||
|
header: Label {
|
||||||
|
text: qsTr("Page 2")
|
||||||
|
font.pixelSize: Qt.application.font.pixelSize * 2
|
||||||
|
padding: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("You are on Page 2.")
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
40
samples/hosting/native/main.cpp
Normal file
40
samples/hosting/native/main.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <Hosting/CoreHost.h>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
static int runCallback(QGuiApplication* app, QQmlApplicationEngine* engine)
|
||||||
|
{
|
||||||
|
engine->load(QUrl(QStringLiteral("qrc:/main.qml")));
|
||||||
|
if (engine->rootObjects().isEmpty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return app->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
|
QString netDll = NET_ROOT;
|
||||||
|
netDll.append(QDir::separator());
|
||||||
|
netDll.append("NetHost.dll");
|
||||||
|
|
||||||
|
CoreHost::RunContext runContext;
|
||||||
|
runContext.hostFxrContext = CoreHost::findHostFxr();
|
||||||
|
runContext.managedExe = netDll;
|
||||||
|
// NOTE: You may set entry point to the current executable if
|
||||||
|
// the .NET runtime is deployed side-by-side.
|
||||||
|
runContext.entryPoint = runContext.hostFxrContext.dotnetRoot;
|
||||||
|
runContext.entryPoint.append(CORECLR_DOTNET_EXE_NAME);
|
||||||
|
|
||||||
|
return CoreHost::run(app,
|
||||||
|
engine,
|
||||||
|
runCallback,
|
||||||
|
runContext);
|
||||||
|
}
|
||||||
49
samples/hosting/native/main.qml
Normal file
49
samples/hosting/native/main.qml
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import test 1.0
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
visible: true
|
||||||
|
width: 640
|
||||||
|
height: 480
|
||||||
|
title: qsTr("Tabs")
|
||||||
|
|
||||||
|
SwipeView {
|
||||||
|
id: swipeView
|
||||||
|
anchors.fill: parent
|
||||||
|
currentIndex: tabBar.currentIndex
|
||||||
|
|
||||||
|
Page1Form {
|
||||||
|
}
|
||||||
|
|
||||||
|
Page2Form {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: TabBar {
|
||||||
|
id: tabBar
|
||||||
|
currentIndex: swipeView.currentIndex
|
||||||
|
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("Page 1")
|
||||||
|
}
|
||||||
|
TabButton {
|
||||||
|
text: qsTr("Page 2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 500; running: true; repeat: true
|
||||||
|
onTriggered: {
|
||||||
|
test.testMethod()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestObject {
|
||||||
|
id: test
|
||||||
|
Component.onCompleted: {
|
||||||
|
// Call .NET
|
||||||
|
test.testMethod()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
samples/hosting/native/qml.qrc
Normal file
9
samples/hosting/native/qml.qrc
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>main.qml</file>
|
||||||
|
<file>Page1Form.ui.qml</file>
|
||||||
|
<file>Page2Form.ui.qml</file>
|
||||||
|
<file>main.qml</file>
|
||||||
|
<file>qtquickcontrols2.conf</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
6
samples/hosting/native/qtquickcontrols2.conf
Normal file
6
samples/hosting/native/qtquickcontrols2.conf
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
; This file can be edited to change the style of the application
|
||||||
|
; Read "Qt Quick Controls 2 Configuration File" for details:
|
||||||
|
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
|
||||||
|
|
||||||
|
[Controls]
|
||||||
|
Style=Default
|
||||||
13
samples/hosting/net/NetHost.csproj
Normal file
13
samples/hosting/net/NetHost.csproj
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
<OutDir>$(MSBuildProjectDirectory)/../net-output</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\src\net\Qml.Net\Qml.Net.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
48
samples/hosting/net/NetHost.sln
Normal file
48
samples/hosting/net/NetHost.sln
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.26124.0
|
||||||
|
MinimumVisualStudioVersion = 15.0.26124.0
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetHost", "NetHost.csproj", "{A787B77B-F87B-44A1-AD3D-38E21A92A84A}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qml.Net", "..\..\..\src\net\Qml.Net\Qml.Net.csproj", "{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A787B77B-F87B-44A1-AD3D-38E21A92A84A}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{7258C1D8-8508-4ED9-8F89-5AE2EAEBED9D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
25
samples/hosting/net/Program.cs
Normal file
25
samples/hosting/net/Program.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using Qml.Net;
|
||||||
|
|
||||||
|
namespace NetHost
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
public class TestObject
|
||||||
|
{
|
||||||
|
public void TestMethod()
|
||||||
|
{
|
||||||
|
Console.WriteLine("test method");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Main(string[] _)
|
||||||
|
{
|
||||||
|
return Host.Run(_, (args, app, engine, runCallback) =>
|
||||||
|
{
|
||||||
|
QQmlApplicationEngine.RegisterType<TestObject>("test");
|
||||||
|
return runCallback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/native/QmlNet/Hosting.pri
Normal file
12
src/native/QmlNet/Hosting.pri
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
HEADERS += $$PWD/Hosting/coreclrhost.h \
|
||||||
|
$$PWD/Hosting/CoreHost.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$PWD/Hosting/CoreHost.cpp
|
||||||
|
|
||||||
|
unix {
|
||||||
|
LIBS += -ldl
|
||||||
|
}
|
||||||
|
|
||||||
200
src/native/QmlNet/Hosting/CoreHost.cpp
Normal file
200
src/native/QmlNet/Hosting/CoreHost.cpp
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
#include <Hosting/CoreHost.h>
|
||||||
|
#include <Hosting/coreclrhost.h>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QDirIterator>
|
||||||
|
#include <QVersionNumber>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define HOSTFXR_DLL_NAME "libhostfxr.dylib"
|
||||||
|
#elif _WIN32
|
||||||
|
#define HOSTFXR_DLL_NAME "hostfxr.dll"
|
||||||
|
#else
|
||||||
|
#define HOSTFXR_DLL_NAME "libhostfxr.so"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QList<QString> CoreHost::getPotientialDotnetRoots()
|
||||||
|
{
|
||||||
|
QList<QString> result;
|
||||||
|
#ifdef _WIN32
|
||||||
|
result.push_back("C:\\Program Files\\dotnet");
|
||||||
|
#else
|
||||||
|
result.push_back("/usr/local/share/dotnet");
|
||||||
|
result.push_back("/usr/share/dotnet");
|
||||||
|
result.push_back("/opt/dotnet");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QByteArray dotnetRoot = qgetenv("DOTNET_ROOT");
|
||||||
|
if(!dotnetRoot.isEmpty()) {
|
||||||
|
// We are overriding the roots, forcing ourselves to look in a particular spot.
|
||||||
|
result.clear();
|
||||||
|
result.push_back(dotnetRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreHost::HostFxrContext CoreHost::findHostFxr()
|
||||||
|
{
|
||||||
|
HostFxrContext result;
|
||||||
|
result.success = false;
|
||||||
|
|
||||||
|
QList<QString> roots = getPotientialDotnetRoots();
|
||||||
|
|
||||||
|
for(QString root : roots) {
|
||||||
|
qDebug("looking for %s in root %s", HOSTFXR_DLL_NAME, qPrintable(root));
|
||||||
|
if(!root.endsWith(QDir::separator())) {
|
||||||
|
root.append(QDir::separator());
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo rootInfo(root);
|
||||||
|
if(!rootInfo.exists()) {
|
||||||
|
qDebug("%s doesn't exist", qPrintable(rootInfo.path()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString host = root;
|
||||||
|
host.append("host");
|
||||||
|
host.append(QDir::separator());
|
||||||
|
QFileInfo hostInfo(host);
|
||||||
|
if(!hostInfo.exists()) {
|
||||||
|
qDebug("%s doesn't exist", qPrintable(host));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString fxr = host;
|
||||||
|
fxr.append("fxr");
|
||||||
|
fxr.append(QDir::separator());
|
||||||
|
QFileInfo fxrInfo(fxr);
|
||||||
|
if(!fxrInfo.exists()) {
|
||||||
|
qDebug("%s doesn't exist.", qPrintable(fxr));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString currentFxrLib;
|
||||||
|
QVersionNumber currentFxrLibVersion;
|
||||||
|
|
||||||
|
QDir fxrDir = fxrInfo.dir();
|
||||||
|
fxrDir.setFilter(QDir::Dirs | QDir::NoDot | QDir::NoDotDot);
|
||||||
|
QDirIterator it(fxrDir, QDirIterator::Subdirectories);
|
||||||
|
while(it.hasNext()) {
|
||||||
|
QString fxrVersion = it.next();
|
||||||
|
QFileInfo fxrVersionInfo(fxrVersion);
|
||||||
|
|
||||||
|
fxrVersion.append(QDir::separator());
|
||||||
|
fxrVersion.append(HOSTFXR_DLL_NAME);
|
||||||
|
|
||||||
|
QFileInfo fxrLibInfo(fxrVersion);
|
||||||
|
if(!fxrLibInfo.exists()) {
|
||||||
|
qDebug("%s doesn't exist", qPrintable(fxrLibInfo.absoluteFilePath()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVersionNumber version = QVersionNumber::fromString(fxrVersionInfo.fileName());
|
||||||
|
if(currentFxrLibVersion.isNull() || version > currentFxrLibVersion) {
|
||||||
|
qDebug("found potentional file %s with version %s", qPrintable(fxrLibInfo.absoluteFilePath()), qPrintable((version.toString())));
|
||||||
|
currentFxrLibVersion = version;
|
||||||
|
currentFxrLib = fxrLibInfo.absoluteFilePath();
|
||||||
|
} else {
|
||||||
|
qDebug("ignore file %s with version %s", qPrintable(fxrLibInfo.absoluteFilePath()), qPrintable((version.toString())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!currentFxrLib.isEmpty()) {
|
||||||
|
qDebug("returning hostfx lib: %s", qPrintable(currentFxrLib));
|
||||||
|
result.success = true;
|
||||||
|
result.hostFxrLib = currentFxrLib;
|
||||||
|
result.dotnetRoot = root;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CoreHost::run(QGuiApplication& app, QQmlApplicationEngine& engine, runCallback runCallback, RunContext runContext)
|
||||||
|
{
|
||||||
|
QList<QString> execArgs;
|
||||||
|
execArgs.push_back(runContext.entryPoint);
|
||||||
|
execArgs.push_back("exec");
|
||||||
|
execArgs.push_back(runContext.managedExe);
|
||||||
|
|
||||||
|
QString appPtr;
|
||||||
|
appPtr.sprintf("%llu", (quintptr)&app);
|
||||||
|
QString enginePtr;
|
||||||
|
enginePtr.sprintf("%llu", (quintptr)&engine);
|
||||||
|
QString callbackPtr;
|
||||||
|
callbackPtr.sprintf("%llu", (quintptr)runCallback);
|
||||||
|
|
||||||
|
execArgs.push_back(appPtr);
|
||||||
|
execArgs.push_back(enginePtr);
|
||||||
|
execArgs.push_back(callbackPtr);
|
||||||
|
|
||||||
|
for (QString arg : runContext.args) {
|
||||||
|
execArgs.push_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const CORECLR_CHAR_TYPE*> hostFxrArgs;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
for (QString arg : execArgs) {
|
||||||
|
hostFxrArgs.push_back(arg.utf16());
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
QList<QByteArray> execArgs8bit;
|
||||||
|
for (QString arg : execArgs) {
|
||||||
|
execArgs8bit.push_back(arg.toLocal8Bit());
|
||||||
|
}
|
||||||
|
for (QByteArray arg : execArgs8bit) {
|
||||||
|
hostFxrArgs.push_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hostfxr_main_ptr hostfxr_main = nullptr;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
HMODULE dll = LoadLibraryA(qPrintable(runContext.hostFxrContext.hostFxrLib));
|
||||||
|
if(dll == nullptr) {
|
||||||
|
qCritical("Couldn't load lib at %s", qPrintable(runContext.hostFxrContext.hostFxrLib));
|
||||||
|
return LoadHostFxrResult::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostfxr_main = reinterpret_cast<hostfxr_main_ptr>(GetProcAddress(dll, "hostfxr_main"));
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void* dll = dlopen(qPrintable(runContext.hostFxrContext.hostFxrLib), RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if(dll == nullptr) {
|
||||||
|
qCritical("Couldn't load lib at %s", qPrintable(runContext.hostFxrContext.hostFxrLib));
|
||||||
|
return LoadHostFxrResult::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostfxr_main = reinterpret_cast<hostfxr_main_ptr>(dlsym(dll, "hostfxr_main"));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(hostfxr_main == nullptr) {
|
||||||
|
qCritical("Couldn't load 'hostfxr_main' from %s", qPrintable(runContext.hostFxrContext.hostFxrLib));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = hostfxr_main(static_cast<int>(hostFxrArgs.size()), &hostFxrArgs[0]);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
FreeLibrary(dll);
|
||||||
|
#else
|
||||||
|
dlclose(dll);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
44
src/native/QmlNet/Hosting/CoreHost.h
Normal file
44
src/native/QmlNet/Hosting/CoreHost.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef COREHOST_H
|
||||||
|
#define COREHOST_H
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <Hosting/coreclrhost.h>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define CORECLR_DOTNET_EXE_NAME "dotnet.exe"
|
||||||
|
#else
|
||||||
|
#define CORECLR_DOTNET_EXE_NAME "dotnet"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CoreHost : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
struct HostFxrContext {
|
||||||
|
bool success;
|
||||||
|
QString dotnetRoot;
|
||||||
|
QString hostFxrLib;
|
||||||
|
};
|
||||||
|
struct RunContext {
|
||||||
|
HostFxrContext hostFxrContext;
|
||||||
|
QString entryPoint;
|
||||||
|
QString managedExe;
|
||||||
|
QList<QString> args;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LoadHostFxrResult
|
||||||
|
{
|
||||||
|
Loaded,
|
||||||
|
AlreadyLoaded,
|
||||||
|
Failed
|
||||||
|
};
|
||||||
|
typedef int (*runCallback)(QGuiApplication* app, QQmlApplicationEngine* engine);
|
||||||
|
|
||||||
|
static QList<QString> getPotientialDotnetRoots();
|
||||||
|
static HostFxrContext findHostFxr();
|
||||||
|
static int run(QGuiApplication& app, QQmlApplicationEngine& engine, runCallback runCallback, RunContext runContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
80
src/native/QmlNet/Hosting/coreclrhost.h
Normal file
80
src/native/QmlNet/Hosting/coreclrhost.h
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
//
|
||||||
|
// APIs for hosting CoreCLR
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef CORECLR_HOST_H
|
||||||
|
#define CORECLR_HOST_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef unsigned short CORECLR_CHAR_TYPE;
|
||||||
|
#else
|
||||||
|
typedef char CORECLR_CHAR_TYPE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For each hosting API, we define a function prototype and a function pointer
|
||||||
|
// The prototype is useful for implicit linking against the dynamic coreclr
|
||||||
|
// library and the pointer for explicit dynamic loading (dlopen, LoadLibrary)
|
||||||
|
#define CORECLR_HOSTING_API(function, ...) \
|
||||||
|
extern "C" int function(__VA_ARGS__); \
|
||||||
|
typedef int (*function##_ptr)(__VA_ARGS__)
|
||||||
|
|
||||||
|
CORECLR_HOSTING_API(coreclr_initialize,
|
||||||
|
const char* exePath,
|
||||||
|
const char* appDomainFriendlyName,
|
||||||
|
int propertyCount,
|
||||||
|
const char** propertyKeys,
|
||||||
|
const char** propertyValues,
|
||||||
|
void** hostHandle,
|
||||||
|
unsigned int* domainId);
|
||||||
|
|
||||||
|
CORECLR_HOSTING_API(coreclr_shutdown,
|
||||||
|
void* hostHandle,
|
||||||
|
unsigned int domainId);
|
||||||
|
|
||||||
|
CORECLR_HOSTING_API(coreclr_shutdown_2,
|
||||||
|
void* hostHandle,
|
||||||
|
unsigned int domainId,
|
||||||
|
int* latchedExitCode);
|
||||||
|
|
||||||
|
CORECLR_HOSTING_API(coreclr_create_delegate,
|
||||||
|
void* hostHandle,
|
||||||
|
unsigned int domainId,
|
||||||
|
const char* entryPointAssemblyName,
|
||||||
|
const char* entryPointTypeName,
|
||||||
|
const char* entryPointMethodName,
|
||||||
|
void** delegate);
|
||||||
|
|
||||||
|
CORECLR_HOSTING_API(coreclr_execute_assembly,
|
||||||
|
void* hostHandle,
|
||||||
|
unsigned int domainId,
|
||||||
|
int argc,
|
||||||
|
const char** argv,
|
||||||
|
const char* managedAssemblyPath,
|
||||||
|
unsigned int* exitCode);
|
||||||
|
|
||||||
|
// hostfxr
|
||||||
|
CORECLR_HOSTING_API(hostfxr_get_native_search_directories,
|
||||||
|
const int argc,
|
||||||
|
const char* argv[],
|
||||||
|
char buffer[],
|
||||||
|
int buffer_size,
|
||||||
|
int* required_buffer_size);
|
||||||
|
|
||||||
|
CORECLR_HOSTING_API(hostfxr_main_startupinfo,
|
||||||
|
const int argc,
|
||||||
|
const char* argv[],
|
||||||
|
const char* host_path,
|
||||||
|
const char* dotnet_root,
|
||||||
|
const char* app_path);
|
||||||
|
|
||||||
|
CORECLR_HOSTING_API(hostfxr_main,
|
||||||
|
const int argc,
|
||||||
|
const CORECLR_CHAR_TYPE* argv[]);
|
||||||
|
|
||||||
|
#undef CORECLR_HOSTING_API
|
||||||
|
|
||||||
|
#endif // CORECLR_HOST_H
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
Q_DECL_EXPORT void net_test_helper_runQml(QQmlApplicationEngineContainer* qmlEngineContainer, LPWSTR qml) {
|
Q_DECL_EXPORT void net_test_helper_runQml(QQmlApplicationEngineContainer* qmlEngineContainer, LPWSTR qml) {
|
||||||
QQmlComponent component(qmlEngineContainer->qmlEngine.data());
|
QQmlComponent component(qmlEngineContainer->qmlEngine);
|
||||||
QString qmlString = QString::fromUtf16((const char16_t*)qml);
|
QString qmlString = QString::fromUtf16((const char16_t*)qml);
|
||||||
component.setData(qmlString.toUtf8(), QUrl());
|
component.setData(qmlString.toUtf8(), QUrl());
|
||||||
QObject *object = component.create();
|
QObject *object = component.create();
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,32 @@ void GuiThreadContextTriggerCallback::trigger() {
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
Q_DECL_EXPORT QGuiApplicationContainer* qguiapplication_create(NetVariantListContainer* argsContainer) {
|
Q_DECL_EXPORT QGuiApplicationContainer* qguiapplication_create(NetVariantListContainer* argsContainer, QGuiApplication* existingApp) {
|
||||||
|
|
||||||
QGuiApplicationContainer* result = new QGuiApplicationContainer();
|
QGuiApplicationContainer* result = new QGuiApplicationContainer();
|
||||||
|
|
||||||
// Build our args
|
if (existingApp != nullptr) {
|
||||||
if(argsContainer != nullptr) {
|
result->ownsGuiApp = false;
|
||||||
QSharedPointer<NetVariantList> args = argsContainer->list;
|
result->guiApp = existingApp;
|
||||||
for(int x = 0; x < args->count(); x++) {
|
|
||||||
QByteArray arg = args->get(x)->getString().toLatin1();
|
|
||||||
result->args.append(arg);
|
|
||||||
char* cstr = nullptr;
|
|
||||||
cstr = new char [arg.size()+1];
|
|
||||||
strcpy(cstr, arg.data());
|
|
||||||
result->argsPointer.push_back(cstr);
|
|
||||||
}
|
|
||||||
result->argCount = result->args.size();
|
|
||||||
} else {
|
} else {
|
||||||
result->argCount = 0;
|
result->ownsGuiApp = true;
|
||||||
|
// Build our args
|
||||||
|
if(argsContainer != nullptr) {
|
||||||
|
QSharedPointer<NetVariantList> args = argsContainer->list;
|
||||||
|
for(int x = 0; x < args->count(); x++) {
|
||||||
|
QByteArray arg = args->get(x)->getString().toLatin1();
|
||||||
|
result->args.append(arg);
|
||||||
|
char* cstr = nullptr;
|
||||||
|
cstr = new char [arg.size()+1];
|
||||||
|
strcpy(cstr, arg.data());
|
||||||
|
result->argsPointer.push_back(cstr);
|
||||||
|
}
|
||||||
|
result->argCount = result->args.size();
|
||||||
|
} else {
|
||||||
|
result->argCount = 0;
|
||||||
|
}
|
||||||
|
result->guiApp = new QGuiApplication(result->argCount, &result->argsPointer[0], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
result->guiApp = QSharedPointer<QGuiApplication>(new QGuiApplication(result->argCount, &result->argsPointer[0], 0));
|
|
||||||
result->callback = QSharedPointer<GuiThreadContextTriggerCallback>(new GuiThreadContextTriggerCallback());
|
result->callback = QSharedPointer<GuiThreadContextTriggerCallback>(new GuiThreadContextTriggerCallback());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -44,6 +49,10 @@ Q_DECL_EXPORT void qguiapplication_destroy(QGuiApplicationContainer* container)
|
||||||
for (auto i : container->argsPointer) {
|
for (auto i : container->argsPointer) {
|
||||||
delete i;
|
delete i;
|
||||||
}
|
}
|
||||||
|
container->callback.clear();
|
||||||
|
if(container->ownsGuiApp) {
|
||||||
|
delete container->guiApp;
|
||||||
|
}
|
||||||
delete container;
|
delete container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,4 +72,8 @@ Q_DECL_EXPORT void qguiapplication_exit(QGuiApplicationContainer* container, int
|
||||||
container->guiApp->exit(returnCode);
|
container->guiApp->exit(returnCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_DECL_EXPORT QGuiApplication* qguiapplication_internalPointer(QGuiApplicationContainer* container) {
|
||||||
|
return container->guiApp;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ struct QGuiApplicationContainer {
|
||||||
int argCount;
|
int argCount;
|
||||||
QList<QString> args;
|
QList<QString> args;
|
||||||
std::vector<char*> argsPointer;
|
std::vector<char*> argsPointer;
|
||||||
QSharedPointer<QGuiApplication> guiApp;
|
QGuiApplication* guiApp;
|
||||||
|
bool ownsGuiApp;
|
||||||
QSharedPointer<GuiThreadContextTriggerCallback> callback;
|
QSharedPointer<GuiThreadContextTriggerCallback> callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,34 @@ static int netValueTypeNumber = 0;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
Q_DECL_EXPORT QQmlApplicationEngineContainer* qqmlapplicationengine_create() {
|
Q_DECL_EXPORT QQmlApplicationEngineContainer* qqmlapplicationengine_create(QQmlApplicationEngine* existingEngine) {
|
||||||
QSharedPointer<QQmlApplicationEngine> qmlEngine = QSharedPointer<QQmlApplicationEngine>(new QQmlApplicationEngine());
|
bool ownsEngine = true;
|
||||||
|
QQmlApplicationEngine* engine = nullptr;
|
||||||
|
|
||||||
QV4::ExecutionEngine* v4Engine = QQmlEnginePrivate::getV4Engine(qmlEngine.data());
|
if (existingEngine != nullptr) {
|
||||||
|
engine = existingEngine;
|
||||||
|
ownsEngine = false;
|
||||||
|
} else {
|
||||||
|
engine = new QQmlApplicationEngine();
|
||||||
|
ownsEngine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QV4::ExecutionEngine* v4Engine = QQmlEnginePrivate::getV4Engine(engine);
|
||||||
|
|
||||||
QV4::Scope scope(v4Engine);
|
QV4::Scope scope(v4Engine);
|
||||||
QV4::ScopedObject net(scope, v4Engine->memoryManager->allocObject<QV4::NetObject>());
|
QV4::ScopedObject net(scope, v4Engine->memoryManager->allocObject<QV4::NetObject>());
|
||||||
v4Engine->globalObject->defineDefaultProperty("Net", net);;
|
v4Engine->globalObject->defineDefaultProperty("Net", net);;
|
||||||
|
|
||||||
return new QQmlApplicationEngineContainer{qmlEngine};
|
return new QQmlApplicationEngineContainer{
|
||||||
|
engine,
|
||||||
|
ownsEngine
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_DECL_EXPORT void qqmlapplicationengine_destroy(QQmlApplicationEngineContainer* container) {
|
Q_DECL_EXPORT void qqmlapplicationengine_destroy(QQmlApplicationEngineContainer* container) {
|
||||||
|
if(container->ownsEngine) {
|
||||||
|
delete container->qmlEngine;
|
||||||
|
}
|
||||||
delete container;
|
delete container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,4 +194,8 @@ Q_DECL_EXPORT void qqmlapplicationengine_addImportPath(QQmlApplicationEngineCont
|
||||||
container->qmlEngine->addImportPath(pathString);
|
container->qmlEngine->addImportPath(pathString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_DECL_EXPORT QQmlApplicationEngine* qqmlapplicationengine_internalPointer(QQmlApplicationEngineContainer* container) {
|
||||||
|
return container->qmlEngine;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
|
|
||||||
#include <QmlNet.h>
|
#include <QmlNet.h>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QSharedPointer>
|
|
||||||
|
|
||||||
struct QQmlApplicationEngineContainer {
|
struct QQmlApplicationEngineContainer {
|
||||||
QSharedPointer<QQmlApplicationEngine> qmlEngine;
|
QQmlApplicationEngine* qmlEngine;
|
||||||
|
bool ownsEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NET_QQMLAPPLICATIONENGINE_H
|
#endif // NET_QQMLAPPLICATIONENGINE_H
|
||||||
|
|
|
||||||
41
src/net/Qml.Net/Host.cs
Normal file
41
src/net/Qml.Net/Host.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Qml.Net
|
||||||
|
{
|
||||||
|
public static class Host
|
||||||
|
{
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int NativeRunCallbackDelegate(IntPtr app, IntPtr engine);
|
||||||
|
|
||||||
|
public delegate int NetRunCallbackDelegate();
|
||||||
|
|
||||||
|
public static int Run(string[] args, Func<string[], QGuiApplication, QQmlApplicationEngine, NetRunCallbackDelegate, int> action)
|
||||||
|
{
|
||||||
|
if (args.Length < 3)
|
||||||
|
{
|
||||||
|
throw new Exception("Args is invalid, must contain three entries which are pointers to native types.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var appPtr = new IntPtr((long)ulong.Parse(args[0]));
|
||||||
|
var enginePtr = new IntPtr((long)ulong.Parse(args[1]));
|
||||||
|
var callbackPtr = new IntPtr((long)ulong.Parse(args[2]));
|
||||||
|
|
||||||
|
using (var app = new QGuiApplication(appPtr))
|
||||||
|
{
|
||||||
|
using (var engine = new QQmlApplicationEngine(enginePtr))
|
||||||
|
{
|
||||||
|
var runCallback = new NetRunCallbackDelegate(() =>
|
||||||
|
{
|
||||||
|
var callback = Marshal.GetDelegateForFunctionPointer<NativeRunCallbackDelegate>(callbackPtr);
|
||||||
|
// ReSharper disable AccessToDisposedClosure
|
||||||
|
return callback.Invoke(app.InternalPointer, engine.InternalPointer);
|
||||||
|
// ReSharper restore AccessToDisposedClosure
|
||||||
|
});
|
||||||
|
return action(args.Skip(2).ToArray(), app, engine, runCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -33,6 +33,18 @@ namespace Qml.Net
|
||||||
SynchronizationContext.SetSynchronizationContext(new QtSynchronizationContext(this));
|
SynchronizationContext.SetSynchronizationContext(new QtSynchronizationContext(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal QGuiApplication(IntPtr existingApp)
|
||||||
|
:base(CreateFromExisting(existingApp))
|
||||||
|
{
|
||||||
|
TriggerDelegate triggerDelegate = Trigger;
|
||||||
|
_triggerHandle = GCHandle.Alloc(triggerDelegate);
|
||||||
|
|
||||||
|
Interop.QGuiApplication.AddTriggerCallback(Handle, Marshal.GetFunctionPointerForDelegate(triggerDelegate));
|
||||||
|
|
||||||
|
_oldSynchronizationContext = SynchronizationContext.Current;
|
||||||
|
SynchronizationContext.SetSynchronizationContext(new QtSynchronizationContext(this));
|
||||||
|
}
|
||||||
|
|
||||||
public int Exec()
|
public int Exec()
|
||||||
{
|
{
|
||||||
return Interop.QGuiApplication.Exec(Handle);
|
return Interop.QGuiApplication.Exec(Handle);
|
||||||
|
|
@ -62,6 +74,8 @@ namespace Qml.Net
|
||||||
Interop.QGuiApplication.RequestTrigger(Handle);
|
Interop.QGuiApplication.RequestTrigger(Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal IntPtr InternalPointer => Interop.QGuiApplication.InternalPointer(Handle);
|
||||||
|
|
||||||
private void Trigger()
|
private void Trigger()
|
||||||
{
|
{
|
||||||
Action action;
|
Action action;
|
||||||
|
|
@ -79,6 +93,11 @@ namespace Qml.Net
|
||||||
_triggerHandle.Free();
|
_triggerHandle.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IntPtr CreateFromExisting(IntPtr app)
|
||||||
|
{
|
||||||
|
return Interop.QGuiApplication.Create(IntPtr.Zero, app);
|
||||||
|
}
|
||||||
|
|
||||||
private static IntPtr Create(List<string> args)
|
private static IntPtr Create(List<string> args)
|
||||||
{
|
{
|
||||||
if (args == null)
|
if (args == null)
|
||||||
|
|
@ -101,7 +120,7 @@ namespace Qml.Net
|
||||||
strings.Add(variant);
|
strings.Add(variant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Interop.QGuiApplication.Create(strings.Handle);
|
return Interop.QGuiApplication.Create(strings.Handle, IntPtr.Zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,7 +146,7 @@ namespace Qml.Net
|
||||||
internal interface IQGuiApplicationInterop
|
internal interface IQGuiApplicationInterop
|
||||||
{
|
{
|
||||||
[NativeSymbol(Entrypoint = "qguiapplication_create")]
|
[NativeSymbol(Entrypoint = "qguiapplication_create")]
|
||||||
IntPtr Create(IntPtr args);
|
IntPtr Create(IntPtr args, IntPtr existingApp);
|
||||||
[NativeSymbol(Entrypoint = "qguiapplication_destroy")]
|
[NativeSymbol(Entrypoint = "qguiapplication_destroy")]
|
||||||
void Destroy(IntPtr app);
|
void Destroy(IntPtr app);
|
||||||
|
|
||||||
|
|
@ -139,5 +158,7 @@ namespace Qml.Net
|
||||||
void RequestTrigger(IntPtr app);
|
void RequestTrigger(IntPtr app);
|
||||||
[NativeSymbol(Entrypoint = "qguiapplication_exit")]
|
[NativeSymbol(Entrypoint = "qguiapplication_exit")]
|
||||||
void Exit(IntPtr app, int returnCode);
|
void Exit(IntPtr app, int returnCode);
|
||||||
|
[NativeSymbol(Entrypoint = "qguiapplication_internalPointer")]
|
||||||
|
IntPtr InternalPointer(IntPtr app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +10,13 @@ namespace Qml.Net
|
||||||
public sealed class QQmlApplicationEngine : BaseDisposable
|
public sealed class QQmlApplicationEngine : BaseDisposable
|
||||||
{
|
{
|
||||||
public QQmlApplicationEngine()
|
public QQmlApplicationEngine()
|
||||||
:base(Interop.QQmlApplicationEngine.Create())
|
:base(Interop.QQmlApplicationEngine.Create(IntPtr.Zero))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal QQmlApplicationEngine(IntPtr existingEngine)
|
||||||
|
:base(Interop.QQmlApplicationEngine.Create(existingEngine))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -24,6 +30,13 @@ namespace Qml.Net
|
||||||
{
|
{
|
||||||
Interop.QQmlApplicationEngine.LoadData(Handle, data);
|
Interop.QQmlApplicationEngine.LoadData(Handle, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddImportPath(string path)
|
||||||
|
{
|
||||||
|
Interop.QQmlApplicationEngine.AddImportPath(Handle, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IntPtr InternalPointer => Interop.QQmlApplicationEngine.InternalPointer(Handle);
|
||||||
|
|
||||||
public static int RegisterType<T>(string uri, int versionMajor = 1, int versionMinor = 0)
|
public static int RegisterType<T>(string uri, int versionMajor = 1, int versionMinor = 0)
|
||||||
{
|
{
|
||||||
|
|
@ -49,11 +62,6 @@ namespace Qml.Net
|
||||||
InteropBehaviors.RegisterQmlInteropBehavior(new MvvmQmlInteropBehavior(), false);
|
InteropBehaviors.RegisterQmlInteropBehavior(new MvvmQmlInteropBehavior(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddImportPath(string path)
|
|
||||||
{
|
|
||||||
Interop.QQmlApplicationEngine.AddImportPath(Handle, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DisposeUnmanaged(IntPtr ptr)
|
protected override void DisposeUnmanaged(IntPtr ptr)
|
||||||
{
|
{
|
||||||
Interop.QQmlApplicationEngine.Destroy(ptr);
|
Interop.QQmlApplicationEngine.Destroy(ptr);
|
||||||
|
|
@ -63,7 +71,7 @@ namespace Qml.Net
|
||||||
internal interface IQQmlApplicationEngine
|
internal interface IQQmlApplicationEngine
|
||||||
{
|
{
|
||||||
[NativeSymbol(Entrypoint = "qqmlapplicationengine_create")]
|
[NativeSymbol(Entrypoint = "qqmlapplicationengine_create")]
|
||||||
IntPtr Create();
|
IntPtr Create(IntPtr existingEngine);
|
||||||
[NativeSymbol(Entrypoint = "qqmlapplicationengine_destroy")]
|
[NativeSymbol(Entrypoint = "qqmlapplicationengine_destroy")]
|
||||||
void Destroy(IntPtr engine);
|
void Destroy(IntPtr engine);
|
||||||
|
|
||||||
|
|
@ -78,5 +86,8 @@ namespace Qml.Net
|
||||||
|
|
||||||
[NativeSymbol(Entrypoint = "qqmlapplicationengine_addImportPath")]
|
[NativeSymbol(Entrypoint = "qqmlapplicationengine_addImportPath")]
|
||||||
void AddImportPath(IntPtr engine, [MarshalAs(UnmanagedType.LPWStr), CallerFree]string path);
|
void AddImportPath(IntPtr engine, [MarshalAs(UnmanagedType.LPWStr), CallerFree]string path);
|
||||||
|
|
||||||
|
[NativeSymbol(Entrypoint = "qqmlapplicationengine_internalPointer")]
|
||||||
|
IntPtr InternalPointer(IntPtr app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue