使用 C 创建 Windows 服务
时间:2022-07-23
本文章向大家介绍使用 C 创建 Windows 服务,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
使用 C 创建 Windows 服务
最近需要将一些命令行程序包装成后台服务, 本来可以用 .NET 完成, 不过又想尝试一下用 C 语言实 现 Windows 服务, 发现用 C 语言做 Windows 服务也是很容易的, 步骤如下:
1 包含必要的头文件, 并定义一些常量, 代码如下:
#include <windows.h>
#include <stdio.h>
// 服务线程暂停时间;
#define SLEEP_TIME 5000
// 日志文件输入路径
#define LOGFILE "C:\memstatus.txt"
2 写日志文件, 几乎所有的服务都有日志输出, 即使是最简单的服务, 可以说: “无日志不服务!“ 作为一个简单的例子, 仅仅简单的向日志文件输出字符串。
int WriteToLog(char* str) {
FILE* log;
log = fopen(LOGFILE, "a+");
if (log == NULL)
return -1;
fprintf(log, "%sn", str);
fclose(log);
return 0;
}
3 全局服务状态和服务控制处理变量, 这写变量会在多个函数中用到, 所以定义成全局变量。
// 当前服务状态
SERVICE_STATUS ServiceStatus;
// 服务控制处理函数
SERVICE_STATUS_HANDLE ServiceStatusHandle;
4 初始化服务, 作为示例, 仅简单向输出日志。
int InitService() {
int result;
result = WriteToLog("Monitoring started.");
return(result);
}
5 服务控制处理函数, 响应在服务管理器中对服务的操作(停止、重新启动)。
void ServiceControlHandler(DWORD request) {
switch (request) {
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
// 服务停止
WriteToLog("Monitoring stopped.");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
// 向服务管理器汇报服务状态
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
return;
}
6 服务入口函数, 运行在后台服务线程中, 服务的逻辑主要在这个函数中实现。
void ServiceMain(int argc, char** argv) {
// 初始化服务类型、 状态、 接受的控制方法以及期待的返回值
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
// 注册服务控制处理函数
ServiceStatusHandle = RegisterServiceCtrlHandler(
L"MemoryStatus", // 服务名称必须与安装服务时的名称一致;
(LPHANDLER_FUNCTION)ServiceControlHandler
);
if (ServiceStatusHandle == NULL) {
// 服务注册失败
return;
}
// 初始化服务
int error = InitService();
if (error) {
// 初始化服务失败, 设置服务状态为 STOPPED 并返回
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
return;
}
// 现在服务已经成功运行起来了, 向服务管理器汇报状态。
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
MEMORYSTATUS memory;
// 服务线程主循环, 每隔 5 秒钟读取系统内存状态, 输出到日志文件
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
char buffer[16];
GlobalMemoryStatus(&memory);
sprintf(buffer, "%d", memory.dwAvailPhys);
int result = WriteToLog(buffer);
if (result) {
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
return;
}
Sleep(SLEEP_TIME);
}
return;
}
7 最后, 程序入口函数, 只是简单的注册服务入口函数, 然后就退出了。 因为已经想系统注册了服务 入口函数, 系统会继续保留这个进程以运行服务线程, 服务进程不会退出。
int main(int argc, char** argv) {
SERVICE_TABLE_ENTRY entry;
entry.lpServiceName = L"MemoryStatus";
entry.lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
// Start the control dispatcher thread for our service
StartServiceCtrlDispatcher(&entry);
return 0;
}
8 服务安装以及测试, 使用 sc create
命令可以安装服务:
REM 服务名称必须与代码中的服务名称保持一致
SC CREATE MemoryStatus binPath= %PROJECT_OUTPUT_DIR%MemoryStatus.exe
注意: 服务名称必须与代码中的服务名称保持一致, binPath= 之后必须保留一个空格!
服务的启动与关闭可以使用 NET
命令:
NET START MemoryStatus
过几秒钟之后在关闭服务:
NET STOP MemoryStatus
最后, 打开日志文件, 可以看到类似下面的输出:
Monitoring started.
-1446236160
-1438883840
-1437360128
Monitoring stopped.
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 当 Python 爬虫搭配起 Bilibili 唧唧,奇怪的生产力出现了
- 一个简单的小技巧,监控网页所有动态标签创建的调用处
- SAP Spartacus storefrontapp index.html的design time和runtime
- OS开发爱好者福利来了:树莓派上编译C语言,顺便掌握一波硬件知识
- 一个简单易用的图标字体库和CSS框架fontawesome
- OLAP 数据平台 Druid 第一步,编写 Spec 配置
- 搭建 Kubernetes 集群 Dashboard 2.0+ 可视化插件
- Kubernetes 集群基本概念
- 未能幸免!安全容器也存在逃逸风险
- vue中v-for图片src路径错误
- 读书笔记 dotnet 什么时候进行垃圾回收
- Windows系统下ROS1或ROS2获取RTSP视频等功能包
- 本地存储
- 移动端click 延时解决方案
- 移动端返回顶部