This commit is contained in:
朱子楚\zhuzi 2023-03-05 23:39:13 +08:00
parent 891270e6d1
commit b459b9dda6
16 changed files with 248 additions and 106 deletions

View File

@ -6,6 +6,8 @@ FluWindow {
width: 500
height: 600
minimumWidth: 300
minimumHeight: 400
title:"关于"
FluAppBar{

View File

@ -9,11 +9,9 @@ Window {
id:app
color: "#00000000"
Component.onCompleted: {
FluApp.setContextProperty("installHelper",installHelper)
FluApp.init(app,properties)
console.debug(properties.installHelper.applicationFilePath())
FluApp.isDark = false
FluApp.setAppWindow(app)
FluApp.routes = {
"/":"qrc:/MainPage.qml",
"/Setting":"qrc:/SettingPage.qml",
@ -24,7 +22,11 @@ Window {
if(installHelper.isNavigateUninstall()){
FluApp.initialRoute = "/Uninstall"
}else{
FluApp.initialRoute = "/Installer"
if(installHelper.isNavigateInstall()){
FluApp.initialRoute = "/Installer"
}else{
FluApp.initialRoute = "/"
}
}
FluApp.run()
}

View File

@ -11,10 +11,22 @@
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Ole32.lib")
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
using CopyProgressCallback = std::function<void(int currentFile, int totalFiles)>;
QString linkName = "FluentUI.lnk";
QString uninstallLinkName = "Uninstall FluentUI.lnk";
QString fileName = "FluentUI";
InstallHelper* InstallHelper::m_instance = nullptr;
static QString getInstallConfigPath(){
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)+"/install";
}
static void copyDir(const QString& srcPath, const QString& dstPath, CopyProgressCallback callback)
{
QDir srcDir(srcPath);
@ -44,50 +56,76 @@ static void copyDir(const QString& srcPath, const QString& dstPath, CopyProgress
}
}
static void createHome(const QString& exePath,const QString& linkName){
//创建桌面快捷方式
QFile::link(exePath, QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/").append(linkName));
}
static void createUninstallLink(QString exePath, QString path, QString uninstallLinkName){
#ifdef Q_OS_WIN
QString dst = path.append("\\").append(uninstallLinkName);
IShellLink *pShellLink;
QString args = "--uninstall";
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, (LPVOID *)&pShellLink);
if (SUCCEEDED(hres))
{
// 设置快捷方式的目标路径和参数
pShellLink->SetPath(exePath.toStdWString().c_str());
pShellLink->SetArguments(args.toStdWString().c_str());
// 设置快捷方式的描述
pShellLink->SetDescription(L"Fluent Uninstall");
// 获取IPersistFile接口
IPersistFile *pPersistFile;
hres = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID *)&pPersistFile);
if (SUCCEEDED(hres))
{
// 保存快捷方式到文件
hres = pPersistFile->Save(dst.toStdWString().c_str(), TRUE);
pPersistFile->Release();
}
pShellLink->Release();
static QString generateBatFile()
{
QDir pathDir(getInstallConfigPath());
if(!pathDir.exists()){
pathDir.mkdir(getInstallConfigPath());
}
CoUninitialize();
// std::string dst = path.append("\\").append(uninstallLinkName).toStdString();
// QFile::link(exePath,QString::fromStdString(dst + " --uninstall"));
#endif
QString filePath = getInstallConfigPath()+"/uninstall.bat";
QFile batFile(filePath);
if (!batFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Failed to create bat file: " << batFile.errorString();
return "";
}
QTextStream out(&batFile);
out << "@echo off\n";
out << "set PID=%1" << "\n";
out << "tasklist /FI \"PID eq %PID%\" | find /i \"%PID%\"\n";
out << "if \"%ERRORLEVEL%\"==\"0\" (\n";
out << " taskkill /pid %PID%\n";
out << " timeout /t 2 /nobreak >nul\n";
out << " echo The process with PID %PID% has been terminated.\n";
out << ") else (\n";
out << " echo The process with PID %PID% does not exist.\n";
out << ")\n";
out << "rd /s /q %2" <<"\n";
batFile.close();
return filePath;
}
static void createStartMenu(const QString& exePath,const QString& fileName,const QString& linkName){
//创建开始菜单快捷方式
QString startMenuPath=QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).append("/").append(fileName);
static bool registerUninstallProgram(const QString& displayName, const QString& installPath, const QString& version)
{
const QString instalIniPath = getInstallConfigPath()+"/install.ini";
QSettings settings(instalIniPath,QSettings::IniFormat);
settings.setValue("DisplayName", displayName);
settings.setValue("InstallLocation", installPath);
settings.setValue("DisplayVersion", version);
QString uninstallCommand = QString("\"%1\" --uninstall").arg(QCoreApplication::applicationFilePath());
settings.setValue("UninstallString", uninstallCommand);
settings.sync();
return true;
}
static bool unRegisterUninstallProgram(){
const QString instalIniPath = getInstallConfigPath()+"/install.ini";
QFile instalIniFile(instalIniPath);
if(instalIniFile.exists()){
instalIniFile.remove();
}
return true;
}
static void createHome(const QString& exePath){
//创建桌面快捷方式
QFile::link(exePath,QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/").append(linkName));
}
static void removeLink(){
QString linkPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/").append(linkName);
QFile linkHome(linkPath);
if(linkHome.exists()){
linkHome.remove();
}
linkPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).append("/").append(fileName);
QFile linkStartMenu(linkPath);
if(linkStartMenu.exists()){
linkStartMenu.remove();
}
}
static void createStartMenu(const QString& exePath){
QString startMenuPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).append("/").append(fileName);
QDir dir(startMenuPath);
if(!dir.exists())
{
@ -100,39 +138,101 @@ static void createStartMenu(const QString& exePath,const QString& fileName,const
}
static void createUninstallLink(QString exePath, QString path){
#ifdef Q_OS_WIN
QString dst = path.append("\\").append(uninstallLinkName);
IShellLink *pShellLink;
QString args = "--uninstall";
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,IID_IShellLink, (LPVOID *)&pShellLink);
if (SUCCEEDED(hres))
{
pShellLink->SetPath(exePath.toStdWString().c_str());
pShellLink->SetArguments(args.toStdWString().c_str());
pShellLink->SetDescription(L"Fluent Uninstall");
IPersistFile *pPersistFile;
hres = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID *)&pPersistFile);
if (SUCCEEDED(hres))
{
hres = pPersistFile->Save(dst.toStdWString().c_str(), TRUE);
pPersistFile->Release();
}
pShellLink->Release();
}
CoUninitialize();
#endif
}
InstallHelper *InstallHelper::getInstance()
{
if(InstallHelper::m_instance == nullptr){
InstallHelper::m_instance = new InstallHelper;
}
return InstallHelper::m_instance;
}
InstallHelper::InstallHelper(QObject *parent)
: QObject{parent}
{
installing(false);
uninstallSuccess(false);
errorInfo("");
}
bool InstallHelper::isNavigateInstall(){
const QString instalIniPath = getInstallConfigPath()+"/install.ini";
QFile installIniFle(instalIniPath);
if(installIniFle.exists()){
return false;
}
return true;
}
void InstallHelper::install(const QString& path,bool isHome,bool isStartMenu){
qt_ntfs_permission_lookup ++;
QFileInfo folder(path.chopped(8));
bool isWritable = folder.isWritable();
qt_ntfs_permission_lookup --;
qDebug()<<folder.path();
if (!isWritable)
{
errorInfo(QString("无写入权限,请用管理员运行或者更新安装文件夹地址"));
return;
}
installing(true);
QString exePath = path+"\\"+"example.exe";
QtConcurrent::run([=](){
installing(true);
QFuture<void> future = QtConcurrent::run(copyDir,QCoreApplication::applicationDirPath(),path,[=](int currentFile, int totalFiles){
if(currentFile==totalFiles){
QString exePath = path+"\\"+"example.exe";
QString fileName = "FluentUI";
QString linkName = "FluentUI.lnk";
QString uninstallLinkName = "Uninstall FluentUI.lnk";
if(isHome){
createHome(exePath,linkName);
createHome(exePath);
}
if(isStartMenu){
createStartMenu(exePath,fileName,linkName);
createStartMenu(exePath);
}
createUninstallLink(exePath,path,uninstallLinkName);
createUninstallLink(exePath,path);
registerUninstallProgram("FluentUI",path,"1.0.0.0");
}
});
future.waitForFinished();
qDebug()<<QCoreApplication::applicationDirPath();
qDebug()<<path;
installing(false);
QStringList args;
args<<"/c";
args<<exePath;
QProcess::startDetached("cmd.exe",args,"C:/",nullptr);
QCoreApplication::exit();
});
}
void InstallHelper::uninstall(){
QString currentDir = QCoreApplication::applicationDirPath();
QDir dir(currentDir);
dir.removeRecursively();
QString batFile = generateBatFile();
qint64 pid = QCoreApplication::applicationPid();
QString currentDir = QCoreApplication::applicationDirPath().replace("/","\\");
QStringList args;
args<<"/c";
args<<batFile;
args<<QString::number(pid);
args<<currentDir;
removeLink();
unRegisterUninstallProgram();
QProcess::startDetached("cmd.exe",args,"C:/",nullptr);
}

View File

@ -13,6 +13,8 @@ class InstallHelper : public QObject
Q_OBJECT
Q_PROPERTY_AUTO(bool,installing)
Q_PROPERTY_AUTO(bool,uninstallSuccess)
Q_PROPERTY_AUTO(QString,errorInfo)
public:
explicit InstallHelper(QObject *parent = nullptr);
@ -23,12 +25,20 @@ public:
}
Q_INVOKABLE bool isNavigateUninstall(){
return true;
// return QGuiApplication::arguments().contains("--uninstall");
return QGuiApplication::arguments().contains("--uninstall");
// return true;
}
Q_INVOKABLE bool isNavigateInstall();
Q_INVOKABLE QString pid(){
return QString::number(QCoreApplication::applicationPid());
}
Q_INVOKABLE void uninstall();
static InstallHelper *getInstance();
private:
static InstallHelper* m_instance;
};
#endif // INSTALLHELPER_H

View File

@ -34,6 +34,14 @@ FluWindow {
installPath = String(fileDialog.fileUrls[0]).replace("file:///","").replace(RegExp("/",'g'),"\\")
}
}
Connections{
target: installHelper
function onErrorInfoChanged(){
showError(installHelper.errorInfo)
}
}
}
@ -68,8 +76,7 @@ FluWindow {
text:"更改路径"
Layout.rightMargin: 30
onClicked: {
showInfo(installHelper.applicationFilePath())
// fileDialog.open()
fileDialog.open()
}
}
}

View File

@ -109,6 +109,7 @@ FluWindow {
topMargin: 20
bottomMargin: 52
}
boundsBehavior: Flickable.StopAtBounds
clip: true
width: 160
model: nav_items
@ -116,6 +117,7 @@ FluWindow {
height: 38
width: nav_list.width
Rectangle{
color: {
if(FluApp.isDark){
@ -147,22 +149,25 @@ FluWindow {
leftMargin: 6
rightMargin: 6
}
}
MouseArea{
id:item_mouse
hoverEnabled: true
anchors.fill: parent
onClicked: {
nav_list.currentIndex = index
MouseArea{
id:item_mouse
hoverEnabled: true
anchors.fill: parent
onClicked: {
nav_list.currentIndex = index
}
}
FluText{
text:model.text
anchors.centerIn: parent
fontStyle: FluText.Caption
}
}
FluText{
text:model.text
anchors.centerIn: parent
fontStyle: FluText.Caption
}
}
}

View File

@ -30,9 +30,16 @@ FluWindow {
topMargin: 20
}
Item{
width: 1
Layout.preferredWidth : parent.width
Layout.fillHeight: true
FluText{
text:"青山不改,绿水长流,有缘再见"
anchors.centerIn: parent
fontStyle:FluText.TitleLarge
}
}
Rectangle{

View File

@ -1,5 +1,5 @@
QT += quick concurrent
CONFIG += c++11
CONFIG += c++11 qtquickcompiler utf8_source
DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT

View File

@ -1,8 +1,16 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDir>
#include <QProcess>
#include "InstallHelper.h"
QMap<QString, QVariant> properties(){
QMap<QString, QVariant> map;
map["installHelper"] = QVariant::fromValue(QVariant::fromValue(InstallHelper::getInstance()));
return map;
}
int main(int argc, char *argv[])
{
QCoreApplication::setOrganizationName("ZhuZiChu");
@ -11,8 +19,14 @@ int main(int argc, char *argv[])
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qDebug()<<"setContextProperty------->1";
engine.rootContext()->setContextProperty("installHelper",new InstallHelper());
QMapIterator<QString, QVariant> iterator(properties());
while (iterator.hasNext()) {
iterator.next();
QString key = iterator.key();
QVariant value = iterator.value();
engine.rootContext()->setContextProperty(key,value);
}
engine.rootContext()->setContextProperty("properties",properties());
const QUrl url(QStringLiteral("qrc:/App.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {

View File

@ -1,4 +1,8 @@
#ifndef STDAFX_H
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
#pragma execution_character_set("utf-8")
#endif
#ifndef STDAFX_H
#define STDAFX_H
#define Q_PROPERTY_AUTO(TYPE, M) \

View File

@ -25,8 +25,9 @@ FluApp::FluApp(QObject *parent)
isDark(false);
}
void FluApp::setAppWindow(QWindow *window){
appWindow = window;
void FluApp::init(QWindow *window,QMap<QString, QVariant> properties){
this->appWindow = window;
this->properties = properties;
}
void FluApp::run(){
@ -40,6 +41,14 @@ void FluApp::navigate(const QString& route){
}
bool isAppWindow = route == initialRoute();
FramelessView *view = new FramelessView();
QMapIterator<QString, QVariant> iterator(properties);
while (iterator.hasNext()) {
iterator.next();
QString key = iterator.key();
QVariant value = iterator.value();
view->engine()->rootContext()->setContextProperty(key,value);
}
view->setColor(QColor(Qt::transparent));
QObject::connect(view, &QQuickView::statusChanged, view, [&](QQuickView::Status status) {
if (status == QQuickView::Status::Ready) {

View File

@ -27,7 +27,7 @@ public:
Q_INVOKABLE void navigate(const QString& route);
Q_INVOKABLE void setAppWindow(QWindow *window);
Q_INVOKABLE void init(QWindow *window,QMap<QString, QVariant> properties);
Q_SIGNAL void windowReady(FramelessView *view);
@ -37,20 +37,10 @@ public:
Q_INVOKABLE void clipText(const QString& text);
Q_INVOKABLE void setContextProperty(const QString &name, QObject *data){
if(engine){
engine->rootContext()->setContextProperty(name,data);
}
}
void setEngine(QQmlEngine *engine){
this->engine = engine;
}
private:
static FluApp* m_instance;
QQmlEngine *engine;
QMap<QString, QVariant> properties;
QWindow *appWindow;
};

View File

@ -72,6 +72,5 @@ void Fluent::initializeEngine(QQmlEngine *engine, const char *uri)
QGuiApplication::setFont(font);
QFontDatabase::addApplicationFont(":/com.zhuzichu/res/font/fontawesome-webfont.ttf");
FluApp* app = FluApp::getInstance();
app->setEngine(engine);
engine->rootContext()->setContextProperty("FluApp",app);
}

View File

@ -8,13 +8,10 @@ class Fluent: public QObject
{
Q_OBJECT
public:
static Fluent *getInstance();
Q_INVOKABLE QString version() const;
void registerTypes(const char *uri);
void initializeEngine(QQmlEngine *engine, const char *uri);
static Fluent *getInstance();
private:
static Fluent* m_instance;
};

View File

@ -13,6 +13,7 @@ Rectangle {
property color primaryColor : "#0064B0"
signal clicked
radius: 4
color:{
if(FluApp.isDark){
if(disabled){

View File

@ -20,11 +20,6 @@ MouseArea {
propagateComposedEvents: true
z: -65535
onReleased: {
Window.window.width = Window.window.width+1
Window.window.width = Window.window.width-1
}
onPressed :
(mouse)=> {
if (fixedSize) {