首先介绍一个功能函数,用于进程句柄的获取:
windows api manual:CreateToolhelp32Snapshot 函数 (tlhelp32.h) - Win32 apps | Microsoft Learn
#include <windows.h>
#include "tlhelp32.h"
#include <QString>
HANDLE GetProcessHandle(DWORD nID)
{
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, nID);
}
// 获取守护进程句柄
HANDLE GetProcessHandleByName(const QString &name)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot)
{
return nullptr;
}
PROCESSENTRY32 pe = { sizeof(pe) };
BOOL fOk;
for (fOk = Process32First(hSnapshot, &pe); fOk; fOk = Process32Next(hSnapshot, &pe))
{
if (QString::fromWCharArray(pe.szExeFile) == name)
{
CloseHandle(hSnapshot);
return GetProcessHandle(pe.th32ProcessID);
}
}
return nullptr;
}
然后开线程进行检测(这里使用的是继承QThread重写run()的方式):
void DaemonTest::run()
{
STARTUPINFOA si;
//进程对象
PROCESS_INFORMATION pi;
//初始化
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
//构造cmd执行守护进程的字符串
char pCmd[MAX_PATH_NUM] = { 0 };
QFileInfo file(m_strFilePath + QDir::separator() + daemonName);
QString strFilePath = file.filePath();
strcat_s(pCmd, strFilePath.toStdString().c_str());
while (m_bRunning)
{
//检查守护程序是否存在
pi.hProcess = GetProcessHandleByName(daemonName);
if (pi.hProcess == nullptr)
{
// 创建子进程,判断是否执行成功
if (!CreateProcessA(NULL, pCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
// 创建失败
}
}
if (pi.hProcess != nullptr)
{
//无限等待子进程退出
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Sleep(100);
}
}
开启守护进程的方法:
void StartDaemon(const QString &path)
{
// 1、检测守护进程是否已经启动了
if (GetProcessHandleByName(DAEMON_NAME) != nullptr)
{
return;
}
QString batFile = path + QDir::separator() + "StartDaemon.bat";
if (QFile(batFile).exists())
{
QFile(batFile).remove();
}
QFile file(batFile);
if (file.open(QFile::ReadWrite))
{
QString strParam = QString("@echo off \n start /d \"%1\" HiDaemond.exe \"%2\" \n exit").arg(QCoreApplication::applicationDirPath()).arg(QFileInfo(QCoreApplication::applicationFilePath()).fileName());
file.write(strParam.toLocal8Bit());
file.close();
QProcess p;
p.start("cmd.exe", QStringList() << "/c" << batFile);
if (p.waitForStarted())
{
p.waitForFinished(2000);
return;
}
}
else
{
QString strAppPath = QApplication::applicationDirPath();
QStringList arguments;
{
QFileInfo file(QApplication::applicationFilePath());
arguments.append(file.fileName());
}
QFileInfo deamonFile(strAppPath + QDir::separator() + DAEMON_NAME);
if (deamonFile.exists())
{
std::wstring operate = QString("runas").toStdWString();//临时提升管理员权限
std::wstring path = QCoreApplication::applicationDirPath().toStdWString();
std::wstring appName = QFileInfo(QCoreApplication::applicationFilePath()).fileName().toStdWString();;
std::wstring file = deamonFile.filePath().toStdWString();
int ret = reinterpret_cast<int>(ShellExecute(nullptr, operate.c_str(), file.c_str(), appName.c_str(), path.c_str(), SW_SHOWNORMAL));
Q_UNUSED(ret)
}
}
}
杀死进程的方法:
void KillProcess(QString pName)
{
QProcess p;
QString c = "taskkill /im " + pName + " /f"; //exeFileName为要杀死的进程名
p.execute(c);
p.close();
}
管道通信方法:
// ******服务端******
void creatPipe()
{
m_pHandle = CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, PIPE_MAXINSTANCES, 0, 0, 1000, NULL);
if (INVALID_HANDLE_VALUE == m_pHandle)
{
CloseHandle(m_pHandle);
// 创建管道失败
m_pHandle = nullptr;
}
}
void run()
{
// 简单同步实现
while (m_bRunning)
{
OVERLAPPED ovlap;
ZeroMemory(&ovlap, sizeof(OVERLAPPED));
//2. 创建管道连接
if (!ConnectNamedPipe(m_pHandle, &ovlap))
{
if (ERROR_IO_PENDING != GetLastError())
{
Sleep(100);
continue;
}
}
// 这个等待可能非常的久
if (ReadFile(m_pHandle, m_readbuffer, 100, &m_readLenth, NULL) == TRUE)
{
emit parse();
}
DisconnectNamedPipe(m_pHandle);
}
}
// ******客户端******
bool openPipe()
{
if (m_pHandle)
{
CloseHandle(m_pHandle);
}
if (!WaitNamedPipe(PIPE_NAME, PIPE_TIMEOUT))
{
// 当前没有可利用的命名管道实例!
return false;
}
m_pHandle = CreateFile(PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == m_pHandle)
{
// "打开命名管道失败!
m_pHandle = NULL;
return false;
}
return true;
}
void writeFile(PipeWriteType type, const QString & param)
{
if (openPipe())
{
DWORD dwWriteLen = 0;
QString strParam = QString("%1#%2").arg((int)type).arg(param);
if (WriteFile(m_pHandle, strParam.toStdString().c_str(), strParam.length(), &dwWriteLen, NULL))
{
// 写入成功
}
CloseHandle(m_pHandle);
m_pHandle = nullptr;
}
Sleep(200);
}