Qt:Windows编程—Qt实现本地服务管理

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_29542611/article/details/85010235

Qt实现本地服务管理

前言

本节将使用Windows的几个API,使用qt实现 本地服务 简单管理。这里简单介绍下服务。
几乎每一种操作系统都有一种在系统启动时启动的进程机制,这种机制不会依赖于用户的交互。在Windows下,类似的基础称为Windows服务服务是一种程序类型,它在后台运行,服务程序通常可以在本地和通过网络为用户提供一些功能,服务在操作系统启动时就会随之启动的程序

效果

实现效果和Windows 服务管理类似,等会我们用我们写的软件进行服务的启动和暂停,然后刷新windows的服务管理 和我们的操作结果应该是一致的。
在这里插入图片描述
在这里插入图片描述

相关的Windows API

  1. 打开服务管理句柄

SC_HANDLE OpenSCManagerA(
LPCSTR lpMachineName, // computer name,NULL 为 本机
LPCSTR lpDatabaseName, // SCM database name,应该为 SERVICES_ACTIVE_DATABASE,NULL默认也为前面那个
DWORD dwDesiredAccess // 对scm数据库的访问权限 SC_MANAGER_ALL_ACCESS
);
// 成功返回service control manager database的handle
// 对应的关闭函数
BOOL CloseServiceHandle(
SC_HANDLE hSCObject
);

  1. 枚举服务

BOOL EnumServicesStatusExA(
SC_HANDLE hSCManager, // OpenSCManager函数返回的句柄
SC_ENUM_TYPE InfoLevel, // SC_ENUM_PROCESS_INFO
DWORD dwServiceType,// 枚举的服务类型
DWORD dwServiceState, // 枚举指定状态的服务
LPBYTE lpServices, // 指向ENUM_SERVICE_STATUS_PROCESSA类型的指针
DWORD cbBufSize, // The size of the buffer pointed to by the lpServices parameter, in bytes.
LPDWORD pcbBytesNeeded, // 传出参数,当buffer太小,返回实际需要的大小
LPDWORD lpServicesReturned,// 传出参数,返回枚举服务的个数
LPDWORD lpResumeHandle, // 输入输出参数,返回枚举是否成功
LPCSTR pszGroupName // 加载 组名字
);
成功返回非0

  1. 打开服务

SC_HANDLE OpenServiceA(
SC_HANDLE hSCManager,
LPCSTR lpServiceName, // 要打开的服务的名称
DWORD dwDesiredAccess // 访问的权限
);

  1. 启动服务

BOOL StartServiceA(
SC_HANDLE hService, // 启动服务的句柄,有上面获得
DWORD dwNumServiceArgs, // 启动服务的参数个数
LPCSTR *lpServiceArgVectors // 启动服务的参数
);

  1. 停止服务

BOOL ControlService(
SC_HANDLE hService,
DWORD dwControl, // 控制码
LPSERVICE_STATUS lpServiceStatus // 传出参数,返回服务的状态
);

核心代码

刷新表格代码:

void Widget::refreshTable(){
    int count = ui->serviceTable->rowCount();
    // 先清空表
    for(int i = 0; i < count;i++)
        ui->serviceTable->removeRow(0);
    // 清空之前申请的空间
    if(mBuf!=nullptr)
        delete[] mBuf;


    DWORD needLen,serviceNum,result,type;
    BOOL ret;

    // 刷新表格,枚举服务
    if(ui->win32->isChecked()){
        // win32服务
        type = SERVICE_WIN32;
    }else{
        // 驱动服务
        type = SERVICE_DRIVER;
    }

    // 第一次 获取需要的字节长度
    ret = EnumServicesStatusExA(mHSCM,SC_ENUM_PROCESS_INFO ,type
                                ,SERVICE_STATE_ALL,NULL,0,&needLen
                                ,&serviceNum,NULL,NULL);
    mBuf = new char[needLen]{0};
    if( ret == 0){
        // 下面这段switch代码要写,在qt5.9.7版本下 不写就是不行
        switch (GetLastError()) {
        case ERROR_ACCESS_DENIED:
            qDebug() << "ERROR_ACCESS_DENIED";
            break;
        case ERROR_MORE_DATA:
            qDebug() << "ERROR_MORE_DATA";
            break;
        case ERROR_INVALID_PARAMETER:
            qDebug() << "ERROR_INVALID_PARAMETER";
            break;
        case ERROR_INVALID_HANDLE:
            qDebug() << "ERROR_INVALID_HANDLE";
            break;
        case ERROR_INVALID_LEVEL:
            qDebug() << "ERROR_INVALID_LEVEL";
            break;
        case ERROR_SHUTDOWN_IN_PROGRESS:
            qDebug() << "ERROR_SHUTDOWN_IN_PROGRESS";
            break;
        default:
            qDebug() << "other error";
            break;
        }
        // EnumServicesStatusExA 枚举服务API
        ret = EnumServicesStatusExA(mHSCM,SC_ENUM_PROCESS_INFO ,type
                                    ,SERVICE_STATE_ALL,reinterpret_cast<LPBYTE>(mBuf),needLen,&needLen
                                    ,&serviceNum,&result,NULL);

        LPENUM_SERVICE_STATUS_PROCESSA p = reinterpret_cast<LPENUM_SERVICE_STATUS_PROCESSA>(mBuf);

        if(ret == 0){
            qDebug() << "获取服务失败";
        }else{
            qDebug() << "获取服务成功";
            // 往表格中添加数据
            for(DWORD i = 0; i < serviceNum; i++){
                ui->serviceTable->insertRow(i);
                ui->serviceTable->setItem(i,0,new QTableWidgetItem(QString(p[i].lpServiceName)));
                ui->serviceTable->setItem(i,1,new QTableWidgetItem(QString::fromLocal8Bit(p[i].lpDisplayName)));
                QTableWidgetItem* item;
                switch(p[i].ServiceStatusProcess.dwCurrentState){
                case SERVICE_PAUSED:
                    item = new QTableWidgetItem("暂停");
                    break;
                case SERVICE_STOPPED:
                    item = new QTableWidgetItem("停止");
                    break;
                case SERVICE_RUNNING:
                    item = new QTableWidgetItem("运行");
                    break;
                default:
                    item = new QTableWidgetItem("其他");
                    break;
                }
                ui->serviceTable->setItem(i,2,item);
            }
//            delete
        }
    }
}

启动服务

void Widget::on_startBtn_clicked()
{
    // 启动服务
    int row = ui->serviceTable->currentRow();
    LPENUM_SERVICE_STATUS_PROCESSA p =  reinterpret_cast<LPENUM_SERVICE_STATUS_PROCESSA>(mBuf);
    if(p[row].ServiceStatusProcess.dwCurrentState == SERVICE_RUNNING)
        return;

    const char* name = ui->serviceTable->item(row,0)->text().toStdString().c_str();
    SC_HANDLE service = OpenServiceA(mHSCM, name, SERVICE_ALL_ACCESS);
    if(service == nullptr){
        qDebug() << "打开服务失败";
        return;
    }

    // StartServiceA启动服务API
    BOOL ret = StartServiceA(service,0,nullptr);
    if( ret ){
        qDebug() << "启动服务成功";
        ui->serviceTable->setItem(row,2,new QTableWidgetItem("运行"));
        p[row].ServiceStatusProcess.dwCurrentState = SERVICE_RUNNING;
    }else{
        qDebug() << "启动服务失败";
    }
}

停止服务

void Widget::on_stopBtn_clicked()
{
    // 停止服务
    int row = ui->serviceTable->currentRow();
    LPENUM_SERVICE_STATUS_PROCESSA p =  reinterpret_cast<LPENUM_SERVICE_STATUS_PROCESSA>(mBuf);
    if(p[row].ServiceStatusProcess.dwCurrentState == SERVICE_STOPPED)
        return;

    const char* name = ui->serviceTable->item(row,0)->text().toStdString().c_str();
    if( name == nullptr)
        return;

    SC_HANDLE service = OpenServiceA(mHSCM, name, SERVICE_ALL_ACCESS);
    if(service == nullptr){
        qDebug() << "打开服务失败";
        return;
    }

    SERVICE_STATUS status;
    // StartServiceA停止服务API
    BOOL ret = ControlService(service,SERVICE_CONTROL_STOP,&status);
    if( ret ){
        qDebug() << "停止服务成功";
        ui->serviceTable->setItem(row,2,new QTableWidgetItem("停止"));
        p[row].ServiceStatusProcess.dwCurrentState = SERVICE_STOPPED;
    }else{
        qDebug() << "停止服务失败";
    }
}

完整代码

完整工程代码可以在这里下载,也可在github下载

猜你喜欢

转载自blog.csdn.net/qq_29542611/article/details/85010235