logo头像

技术引领生活!

Qt开机自动启

本文于658天之前发表,文中内容可能已经过时。

开机自启动是一个常用需求,本文探讨之..

windows平台

  1. 修改注册表: 不推荐

    • 有些杀软拦截
    • 启动时机较早(当然是启动后),可能有些COM之类的接口调用会失败
  2. 使用计划任务自启动: 不推荐

    • 不利于编程
    • 可设置性最高(甚至不用登陆windows就可以运行)
  3. 使用快捷方式启动: 推荐

    • 编程简单

下面只介绍在方法三的编程


3.1 简单启动
使用QStandardPaths + QFile::link 可以完成该目的
需要注意的是在XP和非XP系统的快捷方式路径不同(分别为Startup和启动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//开机自启动
void runWithWindows(bool autoRun, QString exeName, QString linkName)
{
#ifdef Q_OS_WIN
QString startUpPath = QString("%1/%2")
.arg(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation))
.arg("Startup");

QDir dir;
//XP(中文)路径为"启动"
if(!dir.exists(startUpPath)){
startUpPath = QString("%1/%2")
.arg(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation))
.arg("启动");
}

QString linkFull = QString("%1/%2.lnk")
.arg(startUpPath)
.arg(linkName);

if(autoRun){
//如果文件不一致,则创建
if(QFile::symLinkTarget(linkFull) != exeName){
QFile::link(exeName, linkFull);
}
}
else{
if(QFile::exists(linkFull)){
QFile::remove(linkFull);
}
}
#else

#endif
}

3.2 带参数的启动
上面的方式可用于简单的开机自启,但是如果需要创建带参数的快捷方式就鸡鸡了,查看Qt的源代码qfsfileengine_win.cpp中的bool QFSFileEngine::link(const QString &newName)函数, 发现官方偷懒了没办法自己动手吧…

在pro文件中添加
win32{
LIBS += -lole32
LIBS += -luuid
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#ifdef Q_OS_WIN32
#include <windows.h>
#include <shlobj.h>
#include <shobjidl.h>
#endif

#ifdef Q_OS_WIN32
bool CreateFileShortcut(const QString &linkFullName, const QString &arguments, const QString &workDir, const QString &exeName)
{
QString startUpPath = QString("%1/%2")
.arg(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation))
.arg("Startup");

QDir dir;
if(!dir.exists(startUpPath)){
startUpPath = QString("%1/%2")
.arg(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation))
.arg("启动");
}

QString linkFull = QString("%1/%2.lnk")
.arg(startUpPath)
.arg(exeName);

#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
#if !defined(QT_NO_LIBRARY)
bool ret = false;

QString linkName = linkFullName;
QString pathDir = workDir;
//### assume that they add .lnk
IShellLink *psl;
bool neededCoInit = false;

HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);

if (hres == CO_E_NOTINITIALIZED) { // COM was not initialized
neededCoInit = true;
CoInitialize(NULL);
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&psl);
}

if (SUCCEEDED(hres)) {
hres = psl->SetPath((wchar_t *)linkName.replace(QLatin1Char('/'), QLatin1Char('\\')).utf16());
if (SUCCEEDED(hres)) {
hres = psl->SetWorkingDirectory((wchar_t *)pathDir.replace(QLatin1Char('/'), QLatin1Char('\\')).utf16());
if (SUCCEEDED(hres)) {
if(!arguments.isEmpty()){
psl->SetArguments((wchar_t *)arguments.utf16());
}

IPersistFile *ppf;
hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
if (SUCCEEDED(hres)) {


hres = ppf->Save((wchar_t*)linkFull.utf16(), TRUE);
if (SUCCEEDED(hres))
ret = true;
ppf->Release();
}
}
}
psl->Release();
}
if (!ret)
qDebug() << "create link error";

if (neededCoInit)
CoUninitialize();

return ret;
#else
Q_UNUSED(newName);
return false;
#endif // QT_NO_LIBRARY
#elif defined(Q_OS_WINCE) && !defined(QT_NO_WINCE_SHELLSDK)
QString linkName = newName;
linkName.replace(QLatin1Char('/'), QLatin1Char('\\'));
if (!linkName.endsWith(QLatin1String(".lnk")))
linkName += QLatin1String(".lnk");
QString orgName = fileName(AbsoluteName).replace(QLatin1Char('/'), QLatin1Char('\\'));
// Need to append on our own
orgName.prepend(QLatin1Char('"'));
orgName.append(QLatin1Char('"'));
bool ret = SUCCEEDED(SHCreateShortcut((wchar_t*)linkName.utf16(), (wchar_t*)orgName.utf16()));
if (!ret)
setError(QFile::RenameError, qt_error_string());
return ret;
#else // Q_OS_WINCE && !QT_NO_WINCE_SHELLSDK
Q_UNUSED(newName);
Q_UNIMPLEMENTED();
return false;
#endif // Q_OS_WINRT
}
#endif

Linux平台

这个和windows平台类似(参考了ubuntu下的Stacer软件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void StartUp::setup(bool autoRun, QString path, QString linkName, QString icon)
{
QString autostartPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation).append("/autostart");
QFileInfo fi(autostartPath);

if (fi.isDir()) {
autostartPath.append("/");
}

if (! QDir(autostartPath).exists()) {
QDir().mkdir(autostartPath);
}


QString exePath = QString("%1%2.desktop").arg(autostartPath).arg(linkName);
if(autoRun){
QFile f(exePath);

if(f.open(QIODevice::WriteOnly)){
f.write("[Desktop Entry]\n");
f.write(QString("Name=%1\n").arg(linkName).toUtf8());
f.write(QString("Comment=%1 Linux Version\n").arg(linkName).toUtf8());
f.write(QString("GenericName=%1\n").arg(linkName).toUtf8());
f.write(QString("Terminal=false\n").toUtf8());
f.write(QString("Type=Application\n").toUtf8());
f.write(QString("Exec=%1.sh\n").arg(path).toUtf8());
f.write(QString("MimeType=text/plain;\n").toUtf8());
f.write(QString("Icon=%1\n").arg(icon).toUtf8());
f.write(QString("StartupNotify=true\n").toUtf8());
f.write(QString("Actions=Run;").toUtf8());
f.close();
}

//在桌面创建快捷方式需要用gio命令激活
//gio set ~/Desktop/XXXX.desktop metadata::trusted true
QString desktopPath = QString("%1/%2.desktop")
.arg(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation))
.arg(linkName);

QFile::copy(exePath, desktopPath);
}
else{
QFile::remove(exePath);
}

}

支付宝打赏 微信打赏

您的支持是我前行的动力!