2025-03-12 10:03:16 +08:00
|
|
|
|
|
|
|
|
|
|
/**********************************************************************************
|
|
|
|
|
|
* @file SetupFuncWindows.cpp
|
|
|
|
|
|
* @brief Windows系统设置函数
|
|
|
|
|
|
* @author yikenan
|
|
|
|
|
|
* @versiong 1.0
|
|
|
|
|
|
* @date
|
|
|
|
|
|
**********************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
//< 仅在Win系统下编译
|
|
|
|
|
|
#ifdef OS_WINDOWS
|
|
|
|
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
#include <tchar.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include <QtCore>
|
|
|
|
|
|
|
|
|
|
|
|
#include "SetupFunc.h"
|
|
|
|
|
|
#include "setupCommon.h"
|
2025-03-13 15:19:38 +08:00
|
|
|
|
#include "setup/CommonDef.h"
|
2025-03-12 10:03:16 +08:00
|
|
|
|
|
2025-03-12 14:17:53 +08:00
|
|
|
|
namespace iot_sys
|
2025-03-12 10:03:16 +08:00
|
|
|
|
{
|
2025-03-13 15:19:38 +08:00
|
|
|
|
const static char* g_platform_dir_name = PLATFORM_DIR;
|
2025-03-12 10:03:16 +08:00
|
|
|
|
|
|
|
|
|
|
//< 注册系统服务,并设置自启动
|
|
|
|
|
|
bool regSysService(QString &strErr,QString path)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool bRet = false;
|
|
|
|
|
|
const QString strExec = QDir::toNativeSeparators
|
2025-03-13 15:19:38 +08:00
|
|
|
|
(path + QString("/platform/%1/sys_launcher_srv.exe").arg(PLATFORM_DIR));
|
2025-03-12 10:03:16 +08:00
|
|
|
|
qDebug() << strExec;
|
|
|
|
|
|
|
|
|
|
|
|
//< 判断文件存在
|
|
|
|
|
|
if (!QFile::exists(strExec))
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("文件不存在!") + "\n" + strExec;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//< 打开服务控制管理器
|
|
|
|
|
|
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
|
|
if (NULL == hSCM)
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("打开服务管理器失败,请确认是否具有权限!");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
//< 判断服务是否已存在
|
2025-03-13 15:19:38 +08:00
|
|
|
|
SC_HANDLE hService = ::OpenService(hSCM, g_pTCharLauncherServiceName, SERVICE_QUERY_CONFIG);
|
2025-03-12 10:03:16 +08:00
|
|
|
|
if (NULL == hService)
|
|
|
|
|
|
{
|
|
|
|
|
|
//< 创建服务
|
|
|
|
|
|
|
|
|
|
|
|
//< 使用SERVICE_USER_XXX_PROCESS服务类型,用户登录时启动,不影响共享内存等的使用
|
|
|
|
|
|
//< 若使用SERVICE_WIN32_XXX_PROCESS等服务类型,程序以system用户启动,共享内存被隔离,其他用户访问不到
|
|
|
|
|
|
|
|
|
|
|
|
//< todo 最好是实时库等使用共享内存、互斥锁的程序修改声明方式为Global,突破用户间的隔离,原因:
|
|
|
|
|
|
//< 1、如上面说的,SERVICE_USER_XXX_PROCESS是用户登录时才启动,服务自启的实际意义打折扣;
|
|
|
|
|
|
//< 2、多用户登录时会启动多个实例,而实际上由于端口占用等原因,是起不来的;
|
|
|
|
|
|
//< 3、本程序停止服务时存在困难,见下面unregSysService()中的注释。
|
|
|
|
|
|
hService = ::CreateService(
|
2025-03-13 15:19:38 +08:00
|
|
|
|
hSCM, g_pTCharLauncherServiceName, g_pTCharLauncherServiceName,
|
2025-03-12 10:03:16 +08:00
|
|
|
|
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
|
|
|
|
|
|
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
|
|
|
|
|
|
strExec.toStdWString().c_str(), NULL, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
if (hService == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("注册服务失败,请确认是否具有权限!");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
SERVICE_DESCRIPTION stSrvDesc;
|
2025-03-13 15:19:38 +08:00
|
|
|
|
TCHAR szDesc[] = _T("监控系统加载服务");
|
2025-03-12 10:03:16 +08:00
|
|
|
|
stSrvDesc.lpDescription = szDesc;
|
|
|
|
|
|
if (::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &stSrvDesc))
|
|
|
|
|
|
{
|
|
|
|
|
|
bRet = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::CloseServiceHandle(hService);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("已设置服务自启动,若需重新设置,请先取消!");
|
|
|
|
|
|
::CloseServiceHandle(hService);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::CloseServiceHandle(hSCM);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return bRet;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
//< 设置HMI自启动
|
|
|
|
|
|
bool setHmiAutoStart(QString &strErr,QString path)
|
|
|
|
|
|
{
|
|
|
|
|
|
const QString strExec =QDir::toNativeSeparators
|
|
|
|
|
|
(path + "/sys_startup.exe");
|
|
|
|
|
|
|
|
|
|
|
|
//< 判断文件存在
|
|
|
|
|
|
if (!QFile::exists(strExec))
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("文件不存在!") + "\n" + strExec;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-13 15:19:38 +08:00
|
|
|
|
QSettings objRegSetting(g_pszAutoRunRegPath, QSettings::NativeFormat);
|
2025-03-12 10:03:16 +08:00
|
|
|
|
|
2025-03-13 15:19:38 +08:00
|
|
|
|
if (objRegSetting.contains(g_pszAutoRunHMI))
|
2025-03-12 10:03:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("已设置HMI自启动,若需重新设置,请先取消!");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!objRegSetting.isWritable())
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("注册表不可写,请确认是否具有权限!");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-13 15:19:38 +08:00
|
|
|
|
objRegSetting.setValue(g_pszAutoRunHMI, QString("\"") + strExec + QString("\""));
|
2025-03-12 10:03:16 +08:00
|
|
|
|
|
|
|
|
|
|
if (QSettings::NoError != objRegSetting.status())
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("写入注册表失败!");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------
|
|
|
|
|
|
//< 设置进程管理自启动
|
|
|
|
|
|
bool setSysStartupAutoStart(QString &strErr,QString path)
|
|
|
|
|
|
{
|
|
|
|
|
|
const QString strExec =QDir::toNativeSeparators
|
|
|
|
|
|
(path + "/AddSchtasksSysStarup.bat");
|
|
|
|
|
|
|
|
|
|
|
|
//< 判断文件存在
|
|
|
|
|
|
if (!QFile::exists(strExec))
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("文件不存在!") + "\n" + strExec;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString curWorkPath = QDir::currentPath();
|
|
|
|
|
|
QDir::setCurrent(path); // 切换工作路径
|
|
|
|
|
|
|
|
|
|
|
|
if(QProcess::execute(strExec) != QProcess::NormalExit)
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("脚本执行失败!") + "\n" + strExec;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QDir::setCurrent(curWorkPath); // 恢复工作路径
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool setSysStartupAutoStartByVbs(QString &strErr,QString path)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString vbsTxt;
|
|
|
|
|
|
vbsTxt += "Set WshShell = CreateObject(\"WScript.Shell\" )\n";
|
2025-03-13 15:19:38 +08:00
|
|
|
|
vbsTxt += QString("WshShell.Run \"") + "\"\"" + QDir::toNativeSeparators(path + "\\product\\" + QString(g_platform_dir_name) + "\\sys_startup.exe\"\" -hide") + "\"\n";
|
2025-03-12 10:03:16 +08:00
|
|
|
|
vbsTxt += "Set WshShell = Nothing";
|
|
|
|
|
|
|
2025-03-13 15:19:38 +08:00
|
|
|
|
QFile vbsFile( QDir::toNativeSeparators(QString(g_pszAutoStartSysStartupPath) ) );
|
2025-03-12 10:03:16 +08:00
|
|
|
|
if(!vbsFile.open(QFile::WriteOnly | QFile::Truncate))
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("启动文件无法写入");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(vbsFile.write(vbsTxt.toLocal8Bit()) != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
vbsFile.close();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else{
|
|
|
|
|
|
strErr = QObject::tr("启动文件无法写入");
|
|
|
|
|
|
vbsFile.close();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
//< 创建快捷方式
|
|
|
|
|
|
bool creatShortcut(QString &strErr,QString path)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString prodPath = path + QDir::separator() + "product" + QDir::separator() + g_platform_dir_name;
|
|
|
|
|
|
|
|
|
|
|
|
//<桌面快捷方式
|
|
|
|
|
|
QFile::link(prodPath + "/sys_startup.exe", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).append("/").append("实时监控.lnk"));
|
|
|
|
|
|
//>桌面快捷方式
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
Q_UNUSED(strErr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool createStartProgram(QString &strErr,const QString& path)
|
|
|
|
|
|
{
|
|
|
|
|
|
QString prodPath = path + QDir::separator() + "product" + QDir::separator() + g_platform_dir_name;
|
|
|
|
|
|
QString platPath = path + QDir::separator() + "platform" + QDir::separator() + g_platform_dir_name;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//<开始菜单
|
|
|
|
|
|
QDir dir;
|
2025-03-13 15:19:38 +08:00
|
|
|
|
QString startMenuPath=QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)+"/EMS60";
|
2025-03-12 10:03:16 +08:00
|
|
|
|
dir.mkpath(startMenuPath);
|
|
|
|
|
|
QString startMenuNormalPath = startMenuPath + "/常用工具";
|
|
|
|
|
|
dir.mkpath(startMenuNormalPath);
|
|
|
|
|
|
|
|
|
|
|
|
QFile app;
|
|
|
|
|
|
app.link(platPath + "/sys_dog_auth_check.exe", startMenuNormalPath+"/超级狗检查.lnk");
|
|
|
|
|
|
app.link(prodPath + "/FesSim.exe", startMenuNormalPath+"/前置调试.lnk");
|
|
|
|
|
|
app.link(prodPath + "/debug_tool.exe", startMenuNormalPath+"/工程调试工具.lnk");
|
|
|
|
|
|
app.link(prodPath + "/sys_command.bat", startMenuNormalPath+"/命令窗口.lnk");
|
|
|
|
|
|
|
|
|
|
|
|
QString startMenuProjectPath = startMenuPath + "/工程建模";
|
|
|
|
|
|
dir.mkpath(startMenuProjectPath);
|
|
|
|
|
|
app.link(platPath + "/model_system_config.exe",startMenuProjectPath+"/系统建模.lnk");
|
|
|
|
|
|
app.link(platPath + "/model_studio.exe", startMenuProjectPath+"/设备建模.lnk");
|
|
|
|
|
|
app.link(platPath + "/hmi.exe", startMenuProjectPath+"/画面组态.lnk");
|
|
|
|
|
|
app.link(platPath + "/fbd_designer.exe", startMenuProjectPath+"/逻辑编程.lnk");
|
|
|
|
|
|
app.link(platPath + "/db_manager.exe", startMenuProjectPath+"/工程管理.lnk");
|
|
|
|
|
|
|
|
|
|
|
|
QString startMenuSystemPath = startMenuPath + "/系统监控";
|
|
|
|
|
|
dir.mkpath(startMenuSystemPath);
|
|
|
|
|
|
app.link(prodPath + "/sys_startup.exe", startMenuSystemPath+"/实时监控.lnk");
|
|
|
|
|
|
app.link(platPath + "/hmi_explorer.bat", startMenuSystemPath+"/人机界面.lnk");
|
|
|
|
|
|
|
2025-03-13 15:19:38 +08:00
|
|
|
|
app.link(prodPath + "/" + QString(UNINSTALL_EXEC_NAME), startMenuPath+"/系统卸载.lnk");
|
2025-03-12 10:03:16 +08:00
|
|
|
|
//>开始菜单
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
Q_UNUSED(strErr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool DelDir(QString &path)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(path.isEmpty())
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
QDir dir(path);
|
|
|
|
|
|
if(!dir.exists())
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
dir.setFilter(QDir::AllEntries|QDir::NoDotAndDotDot);
|
|
|
|
|
|
QFileInfoList fileList=dir.entryInfoList();
|
|
|
|
|
|
foreach (QFileInfo fi, fileList)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(fi.isFile())
|
|
|
|
|
|
{
|
|
|
|
|
|
fi.dir().remove(fi.fileName());
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DelDir(fi.absoluteFilePath());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return dir.rmpath(dir.absolutePath());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//< 注册Mysql服务
|
|
|
|
|
|
bool regMysqlService(QString &path,QString &strErr)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool bRet = false;
|
|
|
|
|
|
const QString strExec = QDir::toNativeSeparators
|
|
|
|
|
|
(path + "/mysqld.exe");
|
|
|
|
|
|
|
|
|
|
|
|
//< 判断文件存在
|
|
|
|
|
|
if (!QFile::exists(strExec))
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("文件不存在!") + "\n" + strExec;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//< 打开服务控制管理器
|
|
|
|
|
|
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
|
|
if (NULL == hSCM)
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("打开服务管理器失败,请确认是否具有权限!");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
//< 判断服务是否已存在
|
2025-03-13 15:19:38 +08:00
|
|
|
|
SC_HANDLE hService = ::OpenService(hSCM, g_pTCharLauncherServiceName, SERVICE_QUERY_CONFIG);
|
2025-03-12 10:03:16 +08:00
|
|
|
|
if (NULL == hService)
|
|
|
|
|
|
{
|
|
|
|
|
|
//< 创建服务
|
|
|
|
|
|
|
|
|
|
|
|
//< 使用SERVICE_USER_XXX_PROCESS服务类型,用户登录时启动,不影响共享内存等的使用
|
|
|
|
|
|
//< 若使用SERVICE_WIN32_XXX_PROCESS等服务类型,程序以system用户启动,共享内存被隔离,其他用户访问不到
|
|
|
|
|
|
|
|
|
|
|
|
//< todo 最好是实时库等使用共享内存、互斥锁的程序修改声明方式为Global,突破用户间的隔离,原因:
|
|
|
|
|
|
//< 1、如上面说的,SERVICE_USER_XXX_PROCESS是用户登录时才启动,服务自启的实际意义打折扣;
|
|
|
|
|
|
//< 2、多用户登录时会启动多个实例,而实际上由于端口占用等原因,是起不来的;
|
|
|
|
|
|
//< 3、本程序停止服务时存在困难,见下面unregSysService()中的注释。
|
|
|
|
|
|
hService = ::CreateService(
|
2025-03-13 15:19:38 +08:00
|
|
|
|
hSCM, g_pTCharLauncherServiceName, g_pTCharLauncherServiceName,
|
2025-03-12 10:03:16 +08:00
|
|
|
|
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
|
|
|
|
|
|
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
|
|
|
|
|
|
strExec.toStdWString().c_str(), NULL, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
if (hService == NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("注册服务失败,请确认是否具有权限!");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
SERVICE_DESCRIPTION stSrvDesc;
|
|
|
|
|
|
TCHAR szDesc[] = _T("MySql");
|
|
|
|
|
|
stSrvDesc.lpDescription = szDesc;
|
|
|
|
|
|
if (::ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &stSrvDesc))
|
|
|
|
|
|
{
|
|
|
|
|
|
bRet = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::CloseServiceHandle(hService);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = QObject::tr("Mysql服务已启动!");
|
|
|
|
|
|
::CloseServiceHandle(hService);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::CloseServiceHandle(hSCM);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return bRet;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool regUninstallReg(const QString &iconPath,const QString &version,const QString &uninstallerPath,QString &strErr)
|
|
|
|
|
|
{
|
2025-03-13 15:19:38 +08:00
|
|
|
|
QSettings objRegSetting(g_pszRegUninstallRegPath, QSettings::NativeFormat);
|
2025-03-12 10:03:16 +08:00
|
|
|
|
|
|
|
|
|
|
if(!objRegSetting.isWritable())
|
|
|
|
|
|
{
|
|
|
|
|
|
strErr = "cannot write to registry";
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
objRegSetting.setValue("DisplayIcon",iconPath); // 需要自定义
|
2025-03-13 15:19:38 +08:00
|
|
|
|
objRegSetting.setValue("DisplayName","DiCS-EMS60");
|
2025-03-12 10:03:16 +08:00
|
|
|
|
objRegSetting.setValue("DisplayVersion",version); // 需要拼接
|
2025-03-13 15:19:38 +08:00
|
|
|
|
objRegSetting.setValue("Publisher","BYD CO.LTD");
|
2025-03-12 10:03:16 +08:00
|
|
|
|
objRegSetting.setValue("UninstallString",uninstallerPath); //需要拼接
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-03-13 15:19:38 +08:00
|
|
|
|
} //< namespace iot_sys
|
2025-03-12 10:03:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif //< #ifdef OS_WINDOWS
|