当前位置: 首页 > 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,});
}

相关文章:

Rust编写Windows服务

文章目录 Rust编写Windows服务一&#xff1a;Windows服务程序大致原理二&#xff1a;Rust中编写windows服务三&#xff1a;具体实例 Rust编写Windows服务 编写Windows服务可选语言很多, 其中C#最简单。本着练手Rust语言&#xff0c;尝试用Rust编写一个服务。 一&#xff1a;Win…...

MATLAB 从 R2024B 开始支持树莓派 5

树莓派&#xff08;Raspberry Pi&#xff09;系列是一系列基于单板计算机的微型电脑&#xff0c;由英国的树莓派基金会于 2012 年开始发布。它的目标是提供一个低成本、易于学习和玩耍的平台&#xff0c;用于教育和初学者学习计算机科学和编程。 目前市面上&#xff0c;最新最…...

MiniBlogum项目简介

MiniBlogum项目简介 文章目录 MiniBlogum项目简介一、引言二、技术栈与开发环境三、主要功能&#xff08;一&#xff09;用户注册与登录&#xff08;二&#xff09;查看当前登录用户/作者头像、昵称、Gitee仓库地址&#xff08;三&#xff09;查看博客列表&#xff08;四&#…...

如何用 OBProxy 实现 OceanBase 的最佳路由策略

引言 OBProxy&#xff0c;即OceanBase Database Proxy&#xff0c;也简称为ODP&#xff0c;是 OceanBase数据库的专属服务代理。通过应用OBProxy&#xff0c;由后端OceanBase集群的分布式特性所带来的复杂性得以屏蔽&#xff0c;从而使得访问分布式数据库的体验如同访问单机数…...

new/delete和malloc/free到底有什么区别

new和malloc 文章目录 new和malloc前言一、属性上的区别二、使用上的区别三、内存位置的区别四、返回类型的区别五、分配失败的区别六、扩张内存的区别七、系统调度过程的区别总结 前言 new和malloc的知识点&#xff0c;作为一个嵌入式工程师是必须要了解清楚的。new和malloc的…...

Flutter启动无法运行热重载

当出现这种报错时&#xff0c;大概率是flutter的NO_Proxy出问题。 请忽略上面的Android报错因为我做的是windows开发这个也就不管了哈&#xff0c;解决下面也有解决报错的命令大家执行一下就行。 着重说一下Proxy的问题&#xff0c; 我们看到提示NO_PROXY 没有设置。 这个时候我…...

CSS调整背景

一、设置背景颜色 通过 background-color 属性指定&#xff0c;值可以是十六进制 #ffffff&#xff0c;也可以是rgb(0, 255, 255)&#xff0c;或是颜色名称 "red" div {background-color: red; /* 通过颜色名称设置 */background-color: #ff0000; /* 通过十六进制设…...

FinalShell连接Linux服务器并解决反复输入密码问题

FinalShell是一款由国人开发的SSH客户端工具&#xff0c;它支持多平台&#xff0c;包括Windows、Mac OS X和Linux。FinalShell主要用于一体化服务器管理&#xff0c;它不仅是一个SSH客户端&#xff0c;还具备强大的开发和运维功能&#xff0c;能够充分满足开发和运维的需求。 本…...

实用类工具!分享6款AI论文一键生成器免费8000字

在当前的学术研究和写作领域&#xff0c;AI论文生成工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。千笔-AIPassPaper是一款备受推荐的AI论文一键生成器。 千笔-AIPassPaper是一个一站式…...

vue使用TreeSelect设置带所有父级节点的回显

Element Plus的el-tree-select组件 思路&#xff1a; 选中节点时&#xff0c;给选中的节点赋值 pathLabel&#xff0c;pathLabel 为函数生成的节点名字拼接&#xff0c;数据源中不包含。 在el-tree-select组件中设置 props“{ label: ‘pathLabel’ }” 控制选中时input框中回…...

智能机巢+无人机:自动化巡检技术详解

智能机巢与无人机的结合&#xff0c;在自动化巡检领域展现出了巨大的潜力和优势。以下是对这一技术的详细解析&#xff1a; 一、智能机巢概述 智能机巢&#xff0c;也被称为无人机机场或无人机机巢&#xff0c;是专门为无人机提供停靠、充电、维护等服务的智能化设施。它不仅…...

摩托车加装车载手机充电usb方案/雅马哈USB充电方案开发

长途骑行需要给手机与行车记录仪等设备供电&#xff0c;那么&#xff0c;加装USB充电器就相继在两轮电动车上应用起来了。摩托车加装usb充电方案主要应用于汽车、电动自行车、摩托车、房车、渡轮、游艇等交通工具。提供电动车USB充电器方案/摩托车加装usb充电方案/渡轮加装usb充…...

进阶岛 任务3: LMDeploy 量化部署进阶实践

进阶岛 任务3&#xff1a; LMDeploy 量化部署进阶实践 任务&#xff1a;https://github.com/InternLM/Tutorial/blob/camp3/docs/L2/LMDeploy/task.md 使用结合W4A16量化与kv cache量化的internlm2_5-1_8b-chat模型封装本地API并与大模型进行一次对话&#xff0c;作业截图需包…...

vue 使用jszip,file-saver下载压缩包,自定义文件夹名,文件名打包下载为zip压缩包文件,全局封装公共方法使用。

记录一下后台管理全局封装一个压缩包下载方法&#xff0c;文件夹名自定义&#xff0c;文件名自定义&#xff0c;压缩包名自定义。 安装必要的库 npm install jszip npm install file-saver自定义一个公共方法全局注入 页面使用 /** 下载按钮操作 */handleDownload() {const i…...

计网八股文

1.HTTP和HTTPS的区别 安全性&#xff1a; HTTP&#xff1a;是未加密的协议&#xff0c;意味着数据在传输过程中可以被截获、篡改或监听。它不提供任何数据加密。HTTPS&#xff1a;在HTTP的基础上加入了SSL/TLS协议&#xff0c;提供了数据加密、完整性校验和身份验证。这使得传输…...

[001-03-007].第07节:Redis中的事务

我的后端学习大纲 我的Redis学习大纲 1、Redis事务是什么&#xff1a; 1.可以一次执行多个命令&#xff0c;本质是一组命令的集合。一个事务中的所有命令都会序列化&#xff0c; 按顺序地串行化执行而不会被其他命令插入&#xff0c;不许加塞2.一个队列中&#xff0c;一次性、…...

WLAN实验简述

一&#xff1a;配置生产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 是一个开源的应用容器引擎&#xff0c;它允许开发者将应用程序及其依赖项打包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 或 Windows 操作系统上。D…...

C:字符串函数(续)-学习笔记

穗 一些闲话&#xff1a; 最近玩了这款饿殍-明末千里行&#xff0c;不知大家是否有听过这款游戏&#xff0c;颇有感触&#xff01;&#xff01;&#xff01; 游戏中最让我难以忘怀的便是饿殍穗线的故事&#xff0c;生在如今时代的我之前无法理解杜甫在目睹人间悲剧时的心情&…...

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中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;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 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

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️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

基于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 注意&#xff1a;运行前…...