main
朱子楚\zhuzi 2023-03-05 23:46:46 +08:00
parent b459b9dda6
commit 3cbe2cb509
13 changed files with 2 additions and 555 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +0,0 @@
TempMode
Silent=1
Overwrite=1
Setup=./example.exe

View File

@ -1,3 +0,0 @@
@echo off
WinRAR.exe a FluentUI.exe ../*
rar.exe c -znote.txt FluentUI.exe

View File

@ -10,7 +10,6 @@ Window {
color: "#00000000" color: "#00000000"
Component.onCompleted: { Component.onCompleted: {
FluApp.init(app,properties) FluApp.init(app,properties)
console.debug(properties.installHelper.applicationFilePath())
FluApp.isDark = false FluApp.isDark = false
FluApp.routes = { FluApp.routes = {
"/":"qrc:/MainPage.qml", "/":"qrc:/MainPage.qml",
@ -19,15 +18,7 @@ Window {
"/Installer":"qrc:/Installer.qml", "/Installer":"qrc:/Installer.qml",
"/Uninstall":"qrc:/Uninstall.qml" "/Uninstall":"qrc:/Uninstall.qml"
} }
if(installHelper.isNavigateUninstall()){ FluApp.initialRoute = "/"
FluApp.initialRoute = "/Uninstall"
}else{
if(installHelper.isNavigateInstall()){
FluApp.initialRoute = "/Installer"
}else{
FluApp.initialRoute = "/"
}
}
FluApp.run() FluApp.run()
} }

View File

@ -1,238 +0,0 @@
#include "InstallHelper.h"
#include <QDir>
#include <QCoreApplication>
#include <QtConcurrent>
#include <windows.h>
#include <shobjidl.h>
#include <shlguid.h>
#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);
QDir dstDir(dstPath);
if (!dstDir.exists()) {
dstDir.mkdir(dstPath);
}
QFileInfoList fileInfos = srcDir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
int totalFiles = fileInfos.count();
int currentFile = 0;
foreach (QFileInfo fileInfo, fileInfos) {
currentFile++;
QString srcFilePath = fileInfo.filePath();
QString dstFilePath = dstPath + QDir::separator() + fileInfo.fileName();
if (fileInfo.isDir()) {
copyDir(srcFilePath, dstFilePath, callback);
} else {
QFile dstFile(dstFilePath);
if(dstFile.exists()){
dstFile.remove();
}
QFile::copy(srcFilePath, dstFilePath);
}
if (callback != nullptr) {
callback(currentFile, totalFiles);
}
}
}
static QString generateBatFile()
{
QDir pathDir(getInstallConfigPath());
if(!pathDir.exists()){
pathDir.mkdir(getInstallConfigPath());
}
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 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())
{
dir.mkdir(startMenuPath);
}
if(dir.exists())
{
QFile::link(exePath, startMenuPath.append("/").append(linkName));
}
}
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([=](){
QFuture<void> future = QtConcurrent::run(copyDir,QCoreApplication::applicationDirPath(),path,[=](int currentFile, int totalFiles){
if(currentFile==totalFiles){
if(isHome){
createHome(exePath);
}
if(isStartMenu){
createStartMenu(exePath);
}
createUninstallLink(exePath,path);
registerUninstallProgram("FluentUI",path,"1.0.0.0");
}
});
future.waitForFinished();
QStringList args;
args<<"/c";
args<<exePath;
QProcess::startDetached("cmd.exe",args,"C:/",nullptr);
QCoreApplication::exit();
});
}
void InstallHelper::uninstall(){
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

@ -1,44 +0,0 @@
#ifndef INSTALLHELPER_H
#define INSTALLHELPER_H
#include <QObject>
#include <QGuiApplication>
#include <QDebug>
#include "stdafx.h"
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);
Q_INVOKABLE void install(const QString& path,bool isHome,bool isStartMenu);
Q_INVOKABLE QString applicationFilePath(){
return QGuiApplication::arguments().join(" ");
}
Q_INVOKABLE bool isNavigateUninstall(){
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

@ -1,172 +0,0 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Dialogs 1.3 as Dialogs
import Qt.labs.platform 1.1
import FluentUI 1.0
FluWindow {
id:window
width: 800
height: 400
minimumWidth:800
maximumWidth:800
minimumHeight:400
maximumHeight:400
title:"安装向导"
property string installPath: "C:\\Program Files"
property string installName: "FluentUI"
FluAppBar{
id:appbar
title: "安装向导"
}
Item{
id:data
Dialogs.FileDialog {
id: fileDialog
selectFolder: true
folder: "file:///"+installPath
onAccepted: {
installPath = String(fileDialog.fileUrls[0]).replace("file:///","").replace(RegExp("/",'g'),"\\")
}
}
Connections{
target: installHelper
function onErrorInfoChanged(){
showError(installHelper.errorInfo)
}
}
}
ColumnLayout{
width: parent.width
anchors{
top: appbar.bottom
bottom: parent.bottom
topMargin: 20
}
RowLayout{
width: parent.width
FluText{
text:"安装路径:"
Layout.leftMargin: 30
}
FluTextBox{
id:textbox_path
Layout.preferredHeight: 40
Layout.fillWidth: true
text:installPath+ "\\" +installName
readOnly:true
}
FluButton{
text:"更改路径"
Layout.rightMargin: 30
onClicked: {
fileDialog.open()
}
}
}
FluCheckBox{
id:checkbox_startmenu
Layout.topMargin: 20
Layout.leftMargin: 30
checked: true
text:"创建启动菜单快捷方式"
}
FluCheckBox{
id:checkbox_home
Layout.leftMargin: 30
Layout.topMargin: 5
checked: true
text:"创建桌面图标"
}
Item{
width: 1
Layout.fillHeight: true
}
Rectangle{
Layout.fillWidth: true
border.width: 1
border.color: FluApp.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(238/255,238/255,238/255,1)
height: 60
color: FluApp.isDark ? "#323232" : "#FFFFFF"
RowLayout{
anchors{
right: parent.right
rightMargin: 30
verticalCenter: parent.verticalCenter
}
spacing: 14
FluButton{
text:"取消"
onClicked: {
window.close()
}
}
FluFilledButton{
text:"同意并安装"
onClicked: {
installHelper.install(textbox_path.text,checkbox_home.checked,checkbox_startmenu.checked)
}
}
FluButton{
text:"不安装直接运行"
onClicked: {
FluApp.navigate("/")
window.close()
}
}
}
}
}
Rectangle{
anchors.fill: parent
visible: installHelper.installing
color: "#80000000"
MouseArea{
anchors.fill: parent
hoverEnabled: true
}
FluProgressBar{
id:progress
anchors.centerIn: parent
}
FluText{
text:"正在安装..."
color:"#FFFFFF"
font.pixelSize: 20
anchors{
horizontalCenter: progress.horizontalCenter
bottom: progress.top
bottomMargin: 10
}
}
}
}

View File

@ -1,75 +0,0 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Dialogs 1.3 as Dialogs
import Qt.labs.platform 1.1
import FluentUI 1.0
FluWindow {
id:window
width: 800
height: 400
minimumWidth:800
maximumWidth:800
minimumHeight:400
maximumHeight:400
title:"卸载向导"
FluAppBar{
id:appbar
title: "卸载向导"
}
ColumnLayout{
width: parent.width
anchors{
top: appbar.bottom
bottom: parent.bottom
topMargin: 20
}
Item{
Layout.preferredWidth : parent.width
Layout.fillHeight: true
FluText{
text:"青山不改,绿水长流,有缘再见"
anchors.centerIn: parent
fontStyle:FluText.TitleLarge
}
}
Rectangle{
Layout.fillWidth: true
border.width: 1
border.color: FluApp.isDark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(238/255,238/255,238/255,1)
height: 60
color: FluApp.isDark ? "#323232" : "#FFFFFF"
RowLayout{
anchors{
right: parent.right
rightMargin: 30
verticalCenter: parent.verticalCenter
}
spacing: 14
FluButton{
text:"取消"
onClicked: {
window.close()
}
}
FluButton{
text:"确定要卸载"
onClicked: {
installHelper.uninstall()
}
}
}
}
}
}

View File

@ -4,7 +4,6 @@ CONFIG += c++11 qtquickcompiler utf8_source
DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT DEFINES += QT_DEPRECATED_WARNINGS QT_NO_WARNING_OUTPUT
SOURCES += \ SOURCES += \
InstallHelper.cpp \
main.cpp main.cpp
RESOURCES += qml.qrc RESOURCES += qml.qrc
@ -14,5 +13,4 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target !isEmpty(target.path): INSTALLS += target
HEADERS += \ HEADERS += \
InstallHelper.h \
stdafx.h stdafx.h

View File

@ -3,11 +3,10 @@
#include <QQmlContext> #include <QQmlContext>
#include <QDir> #include <QDir>
#include <QProcess> #include <QProcess>
#include "InstallHelper.h"
QMap<QString, QVariant> properties(){ QMap<QString, QVariant> properties(){
QMap<QString, QVariant> map; QMap<QString, QVariant> map;
map["installHelper"] = QVariant::fromValue(QVariant::fromValue(InstallHelper::getInstance())); // map["installHelper"] = QVariant::fromValue(QVariant::fromValue(InstallHelper::getInstance()));
return map; return map;
} }

View File

@ -24,9 +24,7 @@
<file>res/svg/avatar_10.svg</file> <file>res/svg/avatar_10.svg</file>
<file>res/svg/avatar_11.svg</file> <file>res/svg/avatar_11.svg</file>
<file>res/svg/avatar_12.svg</file> <file>res/svg/avatar_12.svg</file>
<file>Installer.qml</file>
<file>T_Awesome.qml</file> <file>T_Awesome.qml</file>
<file>T_TextBox.qml</file> <file>T_TextBox.qml</file>
<file>Uninstall.qml</file>
</qresource> </qresource>
</RCC> </RCC>