(一)Win32服务程序编写 —— 使用SC命令创建与删除
程序员文章站
2022-04-02 22:57:22
...
慢慢人生路,不走寻常路
每天学习一点点
今天根据教程学了几个服务程序的API,根据视频敲了一遍,自己又写了一遍,在这里做一下总结 ^ _ ^
文章目录:
- 何为服务程序?(网上Copy一下概念)
- 服务程序的编写(源码与详细的注释)
- 使用SC命令创建与删除服务程序
- 不能创建程序与启用不了程序的常见问题解决
用到的Win32 API(这个部分可看可不看):
- SERVICE_TABLE_ENTRY(定义服务进入表)
- StartServiceCtrlDispatcher(开始服务控制分布)
- RegisterServiceCtrlHandle(注册服务控制函数)
- SetServiceStatus(设置服务状态)
- GlobalMemoryStatus(获取内存状态信息)
服务程序的大致思路以这几个API的顺序相连,具体写法将在下面作出详细的解释
一、何为服务程序?
服务程序是指为了帮助用户使用与维护电脑,提供服务性手段并支持其他软件开发而编制的一类程序。服务性程序是一类辅助性的程序
,它提供各种运行所需的服务。
我们可以打开CMD运行services.msc命令打开服务进程观察一下:
如图所示,这些都是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命令创建:
三、使用SC命令创建与删除服务程序
使用sc命令创建的格式为:
sc + create + 服务程序的名字 + binpath= + 程序路径
1. 打开CMD,输入创建命令并且将它启动:
2. 输入service.msc命令,查看我们创建的服务程序:
3. 我们查看一下生成的文件:
4. 删除服务程序,输入sc delete 服务程序名称,即可:
注意:在删除之前,先将服务程序停止(可以手动停止)
四、不能创建程序与启用不了程序的常见问题解决
1. 控制台无法正常创建服务程序(拒绝访问)
解决办法:管理员身份运行CMD
2. 服务没有及时响应启动或控制请求
解决办法:
- 检查代码是否存在问题
- 百度搜索解决办法:
写的不好的地方或者不对的地方,欢迎各位哥哥姐姐留言!
作者:浪子花梦
Time:2020.02.07