当前位置: 首页 > news >正文

Rust编写Windows服务

文章目录

  • Rust编写Windows服务
    • 一:Windows服务程序大致原理
    • 二:Rust中编写windows服务
    • 三:具体实例

Rust编写Windows服务

编写Windows服务可选语言很多, 其中C#最简单。本着练手Rust语言,尝试用Rust编写一个服务。

一:Windows服务程序大致原理

参考官网C/C++创建服务流程
https://learn.microsoft.com/zh-cn/windows/win32/services/service-program-tasks

  • 编写服务程序的main函数
    1. main函数中,填充数据结构 DispatchTable: [[服务名,ServiceMain函数], [NULL, NULL]]
    2. 调用StartServiceCtrlDispatcher( DispatchTable )
int __cdecl _tmain(int argc, TCHAR *argv[])
{ SERVICE_TABLE_ENTRY DispatchTable[] = { { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain }, { NULL, NULL } }; if (!StartServiceCtrlDispatcher( DispatchTable )) { SvcReportEvent(TEXT("StartServiceCtrlDispatcher")); } 
} 
  • 编写 ServiceMain 函数
    1. 注册控制处理函数 RegisterServiceCtrlHandler(SvcCtrlHandler )
    2. 设置服务状态,SERVICE_START_PENDING
    3. 做一些预备工作,比如初始化日志/注册事件等
    4. 设置服务状态,SERVICE_START_RUNNING
    5. 开始loop处理我们自己的代码(loop循环中可以接受3中注册的事件,当通知停止时退出循环)
  • 编写控件处理程序函数
    1. 接受事件管理器发送的消息并处理,比如收到SERVICE_CONTROL_STOP时,使用3中注册的事件句柄发送停止事件

二:Rust中编写windows服务

借用第三方库 windows-service = "0.7.0"
https://crates.io/crates/windows-service
参考windows-service中ping-service示例提取了一个模板,只有替换编写两处/* */代码

use std::{ffi::OsString,sync::mpsc,time::Duration,
};
use windows_service::{define_windows_service,service::{ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,ServiceType,},service_control_handler::{self, ServiceControlHandlerResult},service_dispatcher,
};static SERVICE_NAME: &str = "Rust Demo Service";fn main() -> Result<(), windows_service::Error> {service_dispatcher::start(SERVICE_NAME, ffi_service_main)?;Ok(())
}define_windows_service!(ffi_service_main, my_service_main);fn my_service_main(arguments: Vec<OsString>) {let _ = arguments;/*这里服务还没开始, 可以填写初始化日志文件等操作*/let (shutdown_tx, shutdown_rx) = mpsc::channel();// 对应SvcCtrlHandlerlet _event_handler = move |control_event| -> ServiceControlHandlerResult {match control_event {ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,// 处理停止事件ServiceControl::Stop => {shutdown_tx.send(()).unwrap();ServiceControlHandlerResult::NoError}// 其他用户事件都当作停止事件处理ServiceControl::UserEvent(code) => {if code.to_raw() == 130 {shutdown_tx.send(()).unwrap();}ServiceControlHandlerResult::NoError}_ => ServiceControlHandlerResult::NotImplemented,}};let status_handle = service_control_handler::register(SERVICE_NAME, _event_handler);let status_handle = status_handle.unwrap();let _ = status_handle.set_service_status(ServiceStatus {service_type: ServiceType::OWN_PROCESS,current_state: ServiceState::Running,controls_accepted: ServiceControlAccept::STOP,exit_code: ServiceExitCode::Win32(0),checkpoint: 0,wait_hint: Duration::default(),process_id: None,});loop {/*这里写自己的代码逻辑,下面时处理一次循环后睡眠5秒,若是接受到停止等消息退出循环*/match shutdown_rx.recv_timeout(Duration::from_secs(5)) {Ok(_) | Err(mpsc::RecvTimeoutError::Disconnected) => break,Err(mpsc::RecvTimeoutError::Timeout) => (),}}let _ = status_handle.set_service_status(ServiceStatus {service_type: ServiceType::OWN_PROCESS,current_state: ServiceState::Stopped,controls_accepted: ServiceControlAccept::empty(),exit_code: ServiceExitCode::Win32(0),checkpoint: 0,wait_hint: Duration::default(),process_id: None,});
}

三:具体实例

笔记本策略经常恢复到合上盖子睡眠功能,写个小服务定时设置合上盖子不做任何操作
逻辑比较简单,定时调用WinAPI函数CallNtPowerInformation获取配置信息,不符合当前设置执行修改
完整如下

use std::{ffi::{c_void, OsString},sync::mpsc,time::Duration,
};
use windows::Win32::{Foundation::STATUS_SUCCESS, System::Power::{CallNtPowerInformation, POWER_INFORMATION_LEVEL, SYSTEM_POWER_POLICY}};
use windows_service::{define_windows_service,service::{ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,ServiceType,},service_control_handler::{self, ServiceControlHandlerResult},service_dispatcher,
};static SERVICE_NAME: &str = "Power Lid Service";fn main() -> Result<(), windows_service::Error> {service_dispatcher::start(SERVICE_NAME, ffi_service_main)?;Ok(())
}define_windows_service!(ffi_service_main, my_service_main);fn my_service_main(arguments: Vec<OsString>) {let _ = arguments;let (shutdown_tx, shutdown_rx) = mpsc::channel();let _event_handler = move |control_event| -> ServiceControlHandlerResult {match control_event {ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,ServiceControl::Stop => {shutdown_tx.send(()).unwrap();ServiceControlHandlerResult::NoError}ServiceControl::UserEvent(code) => {if code.to_raw() == 130 {shutdown_tx.send(()).unwrap();}ServiceControlHandlerResult::NoError}_ => ServiceControlHandlerResult::NotImplemented,}};let status_handle = service_control_handler::register(SERVICE_NAME, _event_handler);let status_handle = status_handle.unwrap();let _ = status_handle.set_service_status(ServiceStatus {service_type: ServiceType::OWN_PROCESS,current_state: ServiceState::Running,controls_accepted: ServiceControlAccept::STOP,exit_code: ServiceExitCode::Win32(0),checkpoint: 0,wait_hint: Duration::default(),process_id: None,});loop {unsafe {let mut a: SYSTEM_POWER_POLICY = std::mem::zeroed();let status = CallNtPowerInformation(POWER_INFORMATION_LEVEL { 0: 8 },None,0,Some(&mut a as *mut SYSTEM_POWER_POLICY as *mut c_void),size_of::<SYSTEM_POWER_POLICY>() as u32,);if status != STATUS_SUCCESS {println!("获取电源状态失败: {:x} !", status.0);return;}if a.LidClose.Action.0 == 0 {println!("状态已为0, 忽略");return;} else {println!("状态为{:x}", a.LidClose.Action.0);a.LidClose.Action.0 = 0;let status = CallNtPowerInformation(POWER_INFORMATION_LEVEL { 0: 0 },Some(&mut a as *mut SYSTEM_POWER_POLICY as *mut c_void),size_of::<SYSTEM_POWER_POLICY>() as u32,None,0,);if status != STATUS_SUCCESS {println!("设置ac电源状态失败: {:x} !", status.0);return;} else {println!("设置AC电源状态成功");}let status = CallNtPowerInformation(POWER_INFORMATION_LEVEL { 0: 1 },Some(&mut a as *mut SYSTEM_POWER_POLICY as *mut c_void),size_of::<SYSTEM_POWER_POLICY>() as u32,None,0,);if status != STATUS_SUCCESS {println!("设置dc电源状态失败: {:x} !", status.0);return;} else {println!("设置DC电源状态成功");}}}match shutdown_rx.recv_timeout(Duration::from_secs(5)) {Ok(_) | Err(mpsc::RecvTimeoutError::Disconnected) => break,Err(mpsc::RecvTimeoutError::Timeout) => (),}}let _ = status_handle.set_service_status(ServiceStatus {service_type: ServiceType::OWN_PROCESS,current_state: ServiceState::Stopped,controls_accepted: ServiceControlAccept::empty(),exit_code: ServiceExitCode::Win32(0),checkpoint: 0,wait_hint: Duration::default(),process_id: None,});
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Python精选200Tips:121-125
  • Unity-Transform-坐标转换
  • Prometheus+grafana+kafka_exporter监控kafka运行情况
  • Python酷库之旅-第三方库Pandas(117)
  • 人工智能在现代科技中的应用和未来发展趋势
  • 微信小程序中巧妙使用 wx:if 和 catchtouchmove 实现弹窗禁止页面滑动功能
  • git命令行基础常用指令
  • 嵌入式通信原理—SPI总线通信原理与应用
  • Python数据分析及可视化教程--商城订单为例-适用电商相关进行数据分析---亲测可用!!!!
  • 【AI大模型】ChatGPT模型原理介绍(下)
  • 【ESP32】ESP-IDF开发 | GPIO通用输入输出+LED点灯和按键输入例程
  • Java小区物业管理系统
  • JDK动态代理和CGLIB动态代理有什么区别?
  • 鸿蒙开发之ArkTS 基础三 数组
  • 国际商城系统怎么弄 跨境电商商城怎样上线
  • php的引用
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • Docker 笔记(2):Dockerfile
  • echarts花样作死的坑
  • ES6简单总结(搭配简单的讲解和小案例)
  • interface和setter,getter
  • Redis中的lru算法实现
  • select2 取值 遍历 设置默认值
  • Spring Boot快速入门(一):Hello Spring Boot
  • Vue.js 移动端适配之 vw 解决方案
  • 工作手记之html2canvas使用概述
  • 判断客户端类型,Android,iOS,PC
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 小程序开发之路(一)
  • 白色的风信子
  • const的用法,特别是用在函数前面与后面的区别
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 如何正确理解,内页权重高于首页?
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ​linux启动进程的方式
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (Java入门)学生管理系统
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (Oracle)SQL优化技巧(一):分页查询
  • (windows2012共享文件夹和防火墙设置
  • (强烈推荐)移动端音视频从零到上手(下)
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (万字长文)Spring的核心知识尽揽其中
  • (五)activiti-modeler 编辑器初步优化
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • .DFS.
  • .NET delegate 委托 、 Event 事件,接口回调
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .net和php怎么连接,php和apache之间如何连接
  • .Net下使用 Geb.Video.FFMPEG 操作视频文件
  • .Net中的设计模式——Factory Method模式
  • .NET中统一的存储过程调用方法(收藏)
  • /dev/VolGroup00/LogVol00:unexpected inconsistency;run fsck manually
  • /tmp目录下出现system-private文件夹解决方法