欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(一)Win32服务程序编写 —— 使用SC命令创建与删除

程序员文章站 2022-04-02 22:57:22
...

慢慢人生路,不走寻常路
每天学习一点点
今天根据教程学了几个服务程序的API,根据视频敲了一遍,自己又写了一遍,在这里做一下总结 ^ _ ^


文章目录:

  1. 何为服务程序?(网上Copy一下概念)
  2. 服务程序的编写(源码与详细的注释)
  3. 使用SC命令创建与删除服务程序
  4. 不能创建程序与启用不了程序的常见问题解决

用到的Win32 API(这个部分可看可不看):

  1. SERVICE_TABLE_ENTRY(定义服务进入表)
  2. StartServiceCtrlDispatcher(开始服务控制分布)
  3. RegisterServiceCtrlHandle(注册服务控制函数)
  4. SetServiceStatus(设置服务状态)
  5. GlobalMemoryStatus(获取内存状态信息)
    服务程序的大致思路以这几个API的顺序相连,具体写法将在下面作出详细的解释

一、何为服务程序?

服务程序是指为了帮助用户使用与维护电脑,提供服务性手段并支持其他软件开发而编制的一类程序。服务性程序是一类辅助性的程序,它提供各种运行所需的服务。

我们可以打开CMD运行services.msc命令打开服务进程观察一下:

(一)Win32服务程序编写 —— 使用SC命令创建与删除

如图所示,这些都是Windows中的服务程序.

我们所需要做的事情,就是编写一个程序放到这里面,而服务程序要干的事情由我们来实现,本例就以记录内存大小为样例.


二、服务程序的编写

其中每一行代码我们都做了详细的解释

友情提醒:刚看代码时先看函数,再看变量

#include <Windows.h>
#include <fstream>	// 将获取到的内存信息保存到指定文件中
#include <iostream>

using namespace std;

// 下面到main之间的代码,暂时可不看(方便理解)
const int SLEEP_TIME = 5000;	// 延迟时间
BOOL bFlag = TRUE;  // 标记循环是否结束 

SERVICE_STATUS_HANDLE m_ServiceStatusHandle;	// 服务状态句柄
SERVICE_STATUS m_ServiceStatus;	// 服务状态结构体,保存服务程序的一些信息

// 命令行参数可加可不加
void WINAPI ServiceMain(int argc, char* argv[]);// 服务程序入口函数
void WINAPI ServiceCtrlHandler(DWORD Opcode);	// 服务控制函数(暂停、关机一些命令的控制)
int WriteToLog(char* str);	// 将指定字符串写入文件中

int main()
{
    // 1.第一步:定义服务进入表,设置服务程序的入口函数
    // 可以有多个服务程序,最后一个元素必须为NULL
    SERVICE_TABLE_ENTRY DispatchTable[2];
    DisptchTable[0].lpServiceName = "huameng";	// 服务程序名称
    DisptchTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; // 服务程序入口
    DispatchTable[1].lpServiceName = NULL;
    DispatchTable[1].lpServiceProc = NULL;

    // 2.第二步:开始服务控制分布(类似于窗口消息分布的一个东西)
    // 严格来说,这个并不算是第二步,只是为了便于记忆理解……
    StartServieCtrlDispatcher(DispatchTable);

    return 0;
}

void WINAPI ServiceMain(int argc, char* argv[])
{
    MEMORYSTATUS memstatus;	// 内存状态结构体,存储内存的一些信息
    char str[100];	// 存储一个字符串
    int availmb;	// 将获取到的内存大小 B --> MB转换

    // 初始化服务状态
    m_ServiceStatus.dwServiceType = SERVICE_WIN32;	// Win32类型
    m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;	// 当前状态为开始等待	
    m_ServiceStatus.dwControlAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;	// 接受关机与暂停两种控制
    m_ServiceStatus.dwWin32ExitCode = 0;		// 下面四个默认都为0
    m_ServiceStatus.dwServiceSpecificExitCode = 0;
    m_ServiceStatus.dwCheckPoint = 0;
    m_ServiceStatus.dwWaitHint = 0;

    // 3.第三步:注册服务控制
    m_ServiceStatusHandle = RegisterServiceCtrlHandler("huameng", ServiceCtrlHandler);
    if (m_ServiceStatusHandle == 0)	// 判断是否成功执行
    {
        WriteToLog("RegisterServiceCtrlHandle failed");	// 错误信息写入文件
        return;
    }
    WriteToLog("RegisterServiceCtrlHandle success"); 	// 成功信息写入文件
    m_ServceStatus.dwCurretState = SERVICE_RUNNING;	// 成功运行则把状态设置为运行状态

    SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus); // 设置状态

    bFlag = TRUE;		// 循环条件为真

    memset(str, 0, 100);	// 初始化字符串中的数据
    while (bFlag)
    {
        GlobalMemoryStatus(&memstatus);			// 获取内存状态信息
        availmb = memstatus.dwAvailPhys / 1024 / 1024;	// 将获取的字节转化为M
        sprintf_s(str, 100, "availmb memory is %d MB ", availmb);	// 格式化字符串
        WriteToLog(str);	// 写入文件中
        Sleep(SLEEP_TIME);	// 延迟五秒
    }
    WriteToLog("service stopped");	// 结束循环后,发送一消息给文件
}

void WINAPI ServiceCtrlHandler(DWORD Opcode)
{
    switch (Opcode)
    {
    case SERVICE_CONTROL_STOP:	// 暂停控制
        bFlag = FALSE;			// 循环标志为FASE
        m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;// 状态设置为停止
        break;
    case SERVICE_CONTROL_SHUTDOWN:// 关机控制
        bFlag = FALSE;  		// 循环标志为FASE
        m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;// 状态设置为停止
    	break;
    default:
        break;
    }
    
    // 设置服务状态
    SetServiceStatus(m_ServiceStatusHandle, &m_ServiceStatus);
}

int WriteToLog(char* str)
{
    ofstream fout;
    fout.open("C:\\huameng.txt", ios::out | ios::app);	// 追加的方式打开一个文件

    fout << str << "\n";
    
    fout.close();
    return 0;
}

注意,这是一个服务程序!不可以直接运行!(当然运行了也没什么用)

我们将这个源码进行生成之后,会得到一个.exe文件,这个文件就是我们所需要的服务程序.

将这个文件放在C:的根目录下,方便我们使用SC命令创建:
(一)Win32服务程序编写 —— 使用SC命令创建与删除


三、使用SC命令创建与删除服务程序

使用sc命令创建的格式为:
sc + create + 服务程序的名字 + binpath= + 程序路径

1. 打开CMD,输入创建命令并且将它启动:
(一)Win32服务程序编写 —— 使用SC命令创建与删除

2. 输入service.msc命令,查看我们创建的服务程序:
(一)Win32服务程序编写 —— 使用SC命令创建与删除

3. 我们查看一下生成的文件:

(一)Win32服务程序编写 —— 使用SC命令创建与删除

4. 删除服务程序,输入sc delete 服务程序名称,即可:

(一)Win32服务程序编写 —— 使用SC命令创建与删除

注意:在删除之前,先将服务程序停止(可以手动停止)


四、不能创建程序与启用不了程序的常见问题解决

1. 控制台无法正常创建服务程序(拒绝访问)

(一)Win32服务程序编写 —— 使用SC命令创建与删除

解决办法:管理员身份运行CMD

2. 服务没有及时响应启动或控制请求

(一)Win32服务程序编写 —— 使用SC命令创建与删除

解决办法:

  1. 检查代码是否存在问题
  2. 百度搜索解决办法:
    (一)Win32服务程序编写 —— 使用SC命令创建与删除

写的不好的地方或者不对的地方,欢迎各位哥哥姐姐留言!

作者:浪子花梦
Time:2020.02.07

相关标签: Win32 win32