函数声明
bool removeMyself(const QString &exeFilePath,const QString &targetDir);
函数实现
bool MainWidget::removeMyself(const QString &exeFilePath, const QString &targetDir)
{
#ifdef Q_OS_WIN
const QString batchfile = "D:/uninstall.vbs";
QFile file(batchfile);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
return false;
}
const bool removeTargetDir = true; //删除目标目录
QTextStream batch(&file);
batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n";
batch << "file = WScript.Arguments.Item(0)\n";
batch << "folderpath = WScript.Arguments.Item(1)\n";
batch << "Set folder = fso.GetFolder(folderpath)\n";
batch << "on error resume next\n";
batch << "while fso.FileExists(file)\n";
batch << " fso.DeleteFile(file)\n";
batch << " WScript.Sleep(1000)\n";
batch << "wend\n";
if (!removeTargetDir)
batch << "if folder.SubFolders.Count = 0 and folder.Files.Count = 0 then\n";
batch << " Set folder = Nothing\n";
batch << " fso.DeleteFolder folderpath, true\n";
if (!removeTargetDir)
batch << "end if\n";
batch << "fso.DeleteFile(WScript.ScriptFullName)\n";
file.close();
QStringList arguments;
arguments << QLatin1String("//Nologo") << batchfile; // execute the batchfile
arguments << exeFilePath; //卸载exe文件路径 如:D:/wechat/maintenancetool.exe
arguments << targetDir; //卸载目录路径 如:D:/wechat
return QProcess::startDetached(QLatin1String("cscript"), arguments, QDir::rootPath());
#endif
}
函数调用
auto isok = removeMyself("D:/wechat/maintenancetool.exe","D:/wechat");
qDebug() << "isok = " << isok;
代码来源说明,这段代码来自Qt Installer Framework,在我学习Qt Installer Framework源代码时,提取出来的,因为我也一直想知道如何在windows中删除自身及目录,特别是在想实现自定义卸载软件时需要用到,Qt官方也在代码里吐槽了windows,不能删除自身文件,所以使用了一种比较脏的方法,不管脏不脏,能达到目的,就行了。
如下是Qt源代码
void PackageManagerCorePrivate::deleteMaintenanceTool()
{
QDir resourcePath(QFileInfo(maintenanceToolName()).dir());
resourcePath.remove(QLatin1String("installer.dat"));
QDir installDir(targetDir());
installDir.remove(m_data.settings().maintenanceToolName() + QLatin1String(".dat"));
installDir.remove(QLatin1String("network.xml"));
installDir.remove(m_data.settings().maintenanceToolIniFile());
QInstaller::VerboseWriter::instance()->setFileName(QString());
installDir.remove(m_core->value(QLatin1String("LogFileName"), QLatin1String("InstallationLog.txt")));
#ifdef Q_OS_WIN
// Since Windows does not support that the maintenance tool deletes itself we have to go with a rather dirty hack.
// What we do is to create a batchfile that will try to remove the maintenance tool once per second. Then
// we start that batchfile detached, finished our job and close ourselves. Once that's done the batchfile
// will succeed in deleting our uninstall.exe and, if the installation directory was created but us and if
// it's empty after the uninstall, deletes the installation-directory.
const QString batchfile = QDir::toNativeSeparators(QFileInfo(QDir::tempPath(),
QLatin1String("uninstall.vbs")).absoluteFilePath());
QFile f(batchfile);
if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
throw Error(tr("Cannot prepare removal"));
const bool removeTargetDir = QVariant(m_core->value(scRemoveTargetDir)).toBool();
QTextStream batch(&f);
batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n";
batch << "file = WScript.Arguments.Item(0)\n";
batch << "folderpath = WScript.Arguments.Item(1)\n";
batch << "Set folder = fso.GetFolder(folderpath)\n";
batch << "on error resume next\n";
batch << "while fso.FileExists(file)\n";
batch << " fso.DeleteFile(file)\n";
batch << " WScript.Sleep(1000)\n";
batch << "wend\n";
if (!removeTargetDir)
batch << "if folder.SubFolders.Count = 0 and folder.Files.Count = 0 then\n";
batch << " Set folder = Nothing\n";
batch << " fso.DeleteFolder folderpath, true\n";
if (!removeTargetDir)
batch << "end if\n";
batch << "fso.DeleteFile(WScript.ScriptFullName)\n";
f.close();
QStringList arguments;
arguments << QLatin1String("//Nologo") << batchfile; // execute the batchfile
arguments << QDir::toNativeSeparators(QFileInfo(installerBinaryPath()).absoluteFilePath());
arguments << targetDir();
if (!QProcessWrapper::startDetached(QLatin1String("cscript"), arguments, QDir::rootPath()))
throw Error(tr("Cannot start removal"));
#else
// every other platform has no problem if we just delete ourselves now
QFile maintenanceTool(QFileInfo(installerBinaryPath()).absoluteFilePath());
maintenanceTool.remove();
# ifdef Q_OS_MACOS
if (QInstaller::isInBundle(installerBinaryPath())) {
const QLatin1String cdUp("/../../..");
removeDirectoryThreaded(QFileInfo(installerBinaryPath() + cdUp).absoluteFilePath());
QFile::remove(QFileInfo(installerBinaryPath() + cdUp).absolutePath()
+ QLatin1String("/") + configurationFileName());
} else
# endif
#endif
{
// finally remove the components.xml, since it still exists now
QFile::remove(QFileInfo(installerBinaryPath()).absolutePath() + QLatin1String("/")
+ configurationFileName());
}
}
其中的英文注释翻译中文是这样说的,
//由于Windows不支持维护工具自动删除,我们不得不采用一种相当肮脏的方法。
//我们要做的是创建一个批处理文件,它将尝试每秒删除一次维护工具。然后
//我们开始分离批处理文件,完成我们的工作并关闭自己。一旦完成了批处理文件
//将成功删除我们的uninstall.exe和,如果安装目录是创建的,但我们和if .exe
//卸载后为空,删除安装目录。