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函数
- main函数中,填充数据结构
DispatchTable: [[服务名,ServiceMain函数], [NULL, NULL]] - 调用
StartServiceCtrlDispatcher( DispatchTable )
- main函数中,填充数据结构
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 函数
- 注册控制处理函数
RegisterServiceCtrlHandler(SvcCtrlHandler ) - 设置服务状态,SERVICE_START_PENDING
- 做一些预备工作,比如初始化日志/注册事件等
- 设置服务状态,SERVICE_START_RUNNING
- 开始loop处理我们自己的代码(loop循环中可以接受3中注册的事件,当通知停止时退出循环)
- 注册控制处理函数
- 编写控件处理程序函数
- 接受事件管理器发送的消息并处理,比如收到
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,});
}相关文章:
Rust编写Windows服务
文章目录 Rust编写Windows服务一:Windows服务程序大致原理二:Rust中编写windows服务三:具体实例 Rust编写Windows服务 编写Windows服务可选语言很多, 其中C#最简单。本着练手Rust语言,尝试用Rust编写一个服务。 一:Win…...
MATLAB 从 R2024B 开始支持树莓派 5
树莓派(Raspberry Pi)系列是一系列基于单板计算机的微型电脑,由英国的树莓派基金会于 2012 年开始发布。它的目标是提供一个低成本、易于学习和玩耍的平台,用于教育和初学者学习计算机科学和编程。 目前市面上,最新最…...
MiniBlogum项目简介
MiniBlogum项目简介 文章目录 MiniBlogum项目简介一、引言二、技术栈与开发环境三、主要功能(一)用户注册与登录(二)查看当前登录用户/作者头像、昵称、Gitee仓库地址(三)查看博客列表(四&#…...
如何用 OBProxy 实现 OceanBase 的最佳路由策略
引言 OBProxy,即OceanBase Database Proxy,也简称为ODP,是 OceanBase数据库的专属服务代理。通过应用OBProxy,由后端OceanBase集群的分布式特性所带来的复杂性得以屏蔽,从而使得访问分布式数据库的体验如同访问单机数…...
new/delete和malloc/free到底有什么区别
new和malloc 文章目录 new和malloc前言一、属性上的区别二、使用上的区别三、内存位置的区别四、返回类型的区别五、分配失败的区别六、扩张内存的区别七、系统调度过程的区别总结 前言 new和malloc的知识点,作为一个嵌入式工程师是必须要了解清楚的。new和malloc的…...
Flutter启动无法运行热重载
当出现这种报错时,大概率是flutter的NO_Proxy出问题。 请忽略上面的Android报错因为我做的是windows开发这个也就不管了哈,解决下面也有解决报错的命令大家执行一下就行。 着重说一下Proxy的问题, 我们看到提示NO_PROXY 没有设置。 这个时候我…...
CSS调整背景
一、设置背景颜色 通过 background-color 属性指定,值可以是十六进制 #ffffff,也可以是rgb(0, 255, 255),或是颜色名称 "red" div {background-color: red; /* 通过颜色名称设置 */background-color: #ff0000; /* 通过十六进制设…...
FinalShell连接Linux服务器并解决反复输入密码问题
FinalShell是一款由国人开发的SSH客户端工具,它支持多平台,包括Windows、Mac OS X和Linux。FinalShell主要用于一体化服务器管理,它不仅是一个SSH客户端,还具备强大的开发和运维功能,能够充分满足开发和运维的需求。 本…...
实用类工具!分享6款AI论文一键生成器免费8000字
在当前的学术研究和写作领域,AI论文生成工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿,还能进行内容优化、查重和排版等操作。千笔-AIPassPaper是一款备受推荐的AI论文一键生成器。 千笔-AIPassPaper是一个一站式…...
vue使用TreeSelect设置带所有父级节点的回显
Element Plus的el-tree-select组件 思路: 选中节点时,给选中的节点赋值 pathLabel,pathLabel 为函数生成的节点名字拼接,数据源中不包含。 在el-tree-select组件中设置 props“{ label: ‘pathLabel’ }” 控制选中时input框中回…...
智能机巢+无人机:自动化巡检技术详解
智能机巢与无人机的结合,在自动化巡检领域展现出了巨大的潜力和优势。以下是对这一技术的详细解析: 一、智能机巢概述 智能机巢,也被称为无人机机场或无人机机巢,是专门为无人机提供停靠、充电、维护等服务的智能化设施。它不仅…...
摩托车加装车载手机充电usb方案/雅马哈USB充电方案开发
长途骑行需要给手机与行车记录仪等设备供电,那么,加装USB充电器就相继在两轮电动车上应用起来了。摩托车加装usb充电方案主要应用于汽车、电动自行车、摩托车、房车、渡轮、游艇等交通工具。提供电动车USB充电器方案/摩托车加装usb充电方案/渡轮加装usb充…...
进阶岛 任务3: LMDeploy 量化部署进阶实践
进阶岛 任务3: LMDeploy 量化部署进阶实践 任务:https://github.com/InternLM/Tutorial/blob/camp3/docs/L2/LMDeploy/task.md 使用结合W4A16量化与kv cache量化的internlm2_5-1_8b-chat模型封装本地API并与大模型进行一次对话,作业截图需包…...
vue 使用jszip,file-saver下载压缩包,自定义文件夹名,文件名打包下载为zip压缩包文件,全局封装公共方法使用。
记录一下后台管理全局封装一个压缩包下载方法,文件夹名自定义,文件名自定义,压缩包名自定义。 安装必要的库 npm install jszip npm install file-saver自定义一个公共方法全局注入 页面使用 /** 下载按钮操作 */handleDownload() {const i…...
计网八股文
1.HTTP和HTTPS的区别 安全性: HTTP:是未加密的协议,意味着数据在传输过程中可以被截获、篡改或监听。它不提供任何数据加密。HTTPS:在HTTP的基础上加入了SSL/TLS协议,提供了数据加密、完整性校验和身份验证。这使得传输…...
[001-03-007].第07节:Redis中的事务
我的后端学习大纲 我的Redis学习大纲 1、Redis事务是什么: 1.可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化, 按顺序地串行化执行而不会被其他命令插入,不许加塞2.一个队列中,一次性、…...
WLAN实验简述
一:配置生产AP1上级接入层交换机LSW3 sys [Huawei]sysname LSW3 [LSW3]undo info-center enable [LSW3]vlan batch 10 100 [LSW3]int g0/0/2 [LSW3-GigabitEthernet0/0/2]port link-type trunk [LSW3-GigabitEthernet0/0/2]port trunk allow-pass vlan 10 100 [LSW…...
Docker简介在Centos和Ubuntu环境下安装Docker
文章目录 1.Docker简介2.Docker镜像与容器3.安装Docker3.1 Centos环境3.2 Ubuntu环境 1.Docker简介 Docker 是一个开源的应用容器引擎,它允许开发者将应用程序及其依赖项打包到一个可移植的容器中,然后发布到任何流行的 Linux 或 Windows 操作系统上。D…...
C:字符串函数(续)-学习笔记
穗 一些闲话: 最近玩了这款饿殍-明末千里行,不知大家是否有听过这款游戏,颇有感触!!! 游戏中最让我难以忘怀的便是饿殍穗线的故事,生在如今时代的我之前无法理解杜甫在目睹人间悲剧时的心情&…...
Depth靶机详解
靶机下载地址 https://www.vulnhub.com/entry/depth-1,213/ 主机发现 arp-scan -l 端口扫描 nmap -sV -A -T4 192.168.229.156 端口利用 http://192.168.229.156:8080/ 目录扫描 dirb "http://192.168.229.156:8080" dirsearch -u "http://192.168.229.15…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...
