慢慢人生路,不走寻常路
每天学习一点点
今天根据教程学了几个服务程序的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命令打开服务进程观察一下:

scvmm创建centos 编写命令创建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命令创建:

scvmm创建centos 编写命令创建sc表_scvmm创建centos_02


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

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

1. 打开CMD,输入创建命令并且将它启动:

scvmm创建centos 编写命令创建sc表_字符串_03

2. 输入service.msc命令,查看我们创建的服务程序:

scvmm创建centos 编写命令创建sc表_字符串_04

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

scvmm创建centos 编写命令创建sc表_服务程序_05

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

scvmm创建centos 编写命令创建sc表_写入文件_06

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


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

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

scvmm创建centos 编写命令创建sc表_scvmm创建centos_07

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

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

scvmm创建centos 编写命令创建sc表_scvmm创建centos_08

解决办法:

  1. 检查代码是否存在问题
  2. 百度搜索解决办法:

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

作者:浪子花梦
Time:2020.02.07