VC++创建windows服务程序
目录
1.关于windows标准可执行程序和服务程序
2.服务相关整理
2.1 VC++编写服务
2.2 服务注册
2.3 服务卸载
2.4 启动服务
2.5 关闭服务
2.6 sc命令
2.7 查看服务
3.标准程序
3.1 后台方式运行标准程序
3.2 查找进程
3.3 终止进程
以前经常在Linux下编写服务器程序,服务器程序大多都是以守护进程方式运行,并且很多都是要开机启动方式进行。最近工作需要编写跨平台的服务,所以就 想了解一下windows下服务开发,通过查询资料发现windows服务完全是另外一回事,windows没有linux那种以&方式运行服务器程序的方式,需要单独使用另外一套api来开发。
1.关于windows标准可执行程序和服务程序
Window 标准的exe可执行程序通常有一个用户界面,Console或GUI,通常由用户来启动或停止.
Windows服务是运行在windows后台指定用户下(默认System)的应用程序,它没有标准的UI界面,相比标准的EXE程序,Windows服务是在服务开始的时候创建,而在服务结束的时候销毁,而且可以设置服务是否与操作系统一起启动,一起关闭。
它支持三种方式:1)自动方式 2)手动方式 3)禁用 。
自动方式的时候,windows服务将在OS启动后自动启动运行,而手动方式则必须手工启动服务,禁用的情况下服务将不能被启动。另外标准的EXE默认使用的当前登录的用户,而windows服务则默认使用System用户,这在对系统资源访问的时候特别需要注意。
Windows Service 是主要用于服务器环境而长期运行的应用程序, 这类程序不需要有用户界面或者任何模拟输出。 任何的用户消息通常都是记录在Windows 事件日志里。Windows Service可以在操作系统启动的时候开始,一直在后台运行,当有需要时也可以手动启动,我们可以通过管理工具里面的服务进行统一管理。当系统启动完毕后,Windows服务并不需要通过登陆页面后才能启动,而我们启动一般的exe文件却要先登陆Windows后才能启动它。
Windows Service 是一种可随 Windows 操作系统启动而启动的,在后台运行的,通常不和用户产生交互的程序。它无法通过双击来运行,类似于 Unix 守护进程(daemon processes),当用户注销时它也不会停止。
Windows 服务由三部分组成:1.一个服务可执行文件;2.一个服务控制程序(SCP);3.服务控制管理器(SCM),
负责在 HKLM\SYSTEM\CurrentControlSet\Services 下创建服务键值。用户可通过 SCP 控制服务的启动、停止、暂停等,SCP 会通过 SCM 调用服务程序。服务程序、服务控制程序(SCP,service control program)和服务控制管理器(SCM,service control manager)组成了Windows服务。我们可以通过服务控制程序操纵服务控制管理器来配置、启动、暂停、停止服务程序。其中服务程序和服务控制程序可以由我们自己来编写扩展,而服务控制管理器(\windows\system32\servics.exe)则是操作系统内置的一个部件。
重点说明:
Windows服务程序其实并不神秘,它只是遵循特定规则编写的一个程序。只要遵循这个特定的规则与服务控制管理器正确的交互,就可实现我们的服务程序。而我们只要能实现一个简单的服务程序,设计一个能处理复杂业务的服务也并非难事,因为从结构上看两者并没有太大的区别。
只要遵循与SCM交互的规则,设计服务程序与设计普通的应用程序几乎没什么区别。
2.服务相关整理
2.1 VC++编写服务
// MyService.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <Windows.h>
#include <iostream>using namespace std;/*
BOOL IsInstalled();
BOOL Install();
BOOL Uninstall();
void LogEvent(LPCTSTR pszFormat, ...);
void WINAPI ServiceMain();
void WINAPI ServiceStrl(DWORD dwOpcode);TCHAR szServiceName[] = _T("MyService");
BOOL bInstall;
SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS status;
DWORD dwThreadID;
SC_HANDLE hSCM;
SC_HANDLE hService;
*//*
OpenSCManager 用于打开服务控制管理器;
CreateService 用于创建服务;
OpenService用于打开已有的服务,返回该服务的句柄;
ControlService则用于控制已打开的服务状态,这里是让服务停止后才删除;
DeleteService 用于删除指定服务。RegisterServiceCtrlHandler 注册服务控制
*///定义全局函数变量
void Init();
BOOL IsInstalled();
BOOL Install();
BOOL Uninstall();
void LogEvent(LPCTSTR pszFormat, ...);
void WINAPI ServiceMain();
void WINAPI ServiceStrl(DWORD dwOpcode);TCHAR szServiceName[] = _T("MyService");
BOOL bInstall;
SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS status;
DWORD dwThreadID;int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{Init();dwThreadID = ::GetCurrentThreadId();SERVICE_TABLE_ENTRY st[] ={{ szServiceName, (LPSERVICE_MAIN_FUNCTION)ServiceMain },{ NULL, NULL }};if (_stricmp(lpCmdLine, "/install") == 0){Install();}else if (_stricmp((LPCTSTR)lpCmdLine, "/uninstall") == 0){Uninstall();}else{if (!::StartServiceCtrlDispatcher(st)){LogEvent(_T("Register Service Main Function Error!"));}}return 0;
}//初始化
void Init()
{hServiceStatus = NULL;status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;status.dwCurrentState = SERVICE_START_PENDING;status.dwControlsAccepted = SERVICE_ACCEPT_STOP;status.dwWin32ExitCode = 0;status.dwServiceSpecificExitCode = 0;status.dwCheckPoint = 0;status.dwWaitHint = 0;
}//服务主函数,这在里进行控制对服务控制的注册
void WINAPI ServiceMain()
{status.dwCurrentState = SERVICE_START_PENDING;status.dwControlsAccepted = SERVICE_ACCEPT_STOP;//注册服务控制 hServiceStatus = RegisterServiceCtrlHandler(szServiceName, ServiceStrl);if (hServiceStatus == NULL){LogEvent(_T("Handler not installed"));return;}SetServiceStatus(hServiceStatus, &status);status.dwWin32ExitCode = S_OK;status.dwCheckPoint = 0;status.dwWaitHint = 0;status.dwCurrentState = SERVICE_RUNNING;SetServiceStatus(hServiceStatus, &status);//模拟服务的运行。应用时将主要任务放于此即可 //可在此写上服务需要执行的代码,一般为死循环 while (1){FILE *p;p = fopen("c:\\log.txt", "ab+");SYSTEMTIME st;GetSystemTime(&st);char time[100] = { 0 };_sntprintf(time, 100, "%4d-%02d-%02d %02d:%02d:%02d\r\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);fwrite(time, strlen(time), 1, p);fclose(p);Sleep(1000);}status.dwCurrentState = SERVICE_STOPPED;SetServiceStatus(hServiceStatus, &status);
}//Description: 服务控制主函数,这里实现对服务的控制,
// 当在服务管理器上停止或其它操作时,将会运行此处代码
void WINAPI ServiceStrl(DWORD dwOpcode)
{switch (dwOpcode){case SERVICE_CONTROL_STOP:status.dwCheckPoint = 1;status.dwCurrentState = SERVICE_STOP_PENDING;SetServiceStatus(hServiceStatus, &status);Sleep(500);status.dwCheckPoint = 0;status.dwCurrentState = SERVICE_STOPPED;SetServiceStatus(hServiceStatus, &status);PostThreadMessage(dwThreadID, WM_CLOSE, 0, 0);break;case SERVICE_CONTROL_PAUSE:break;case SERVICE_CONTROL_CONTINUE:break;case SERVICE_CONTROL_INTERROGATE:break;case SERVICE_CONTROL_SHUTDOWN:exit(0);break;default:LogEvent(_T("Bad service request"));}
}//判断服务是否已经被安装
BOOL IsInstalled()
{BOOL bResult = FALSE;//打开服务控制管理器 SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (hSCM != NULL){//打开服务 SC_HANDLE hService = ::OpenService(hSCM, szServiceName, SERVICE_QUERY_CONFIG);if (hService != NULL){bResult = TRUE;::CloseServiceHandle(hService);}::CloseServiceHandle(hSCM);}return bResult;
}//安装服务函数
BOOL Install()
{//检测是否安装过if (IsInstalled())return TRUE;//打开服务控制管理器 SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (hSCM == NULL){MessageBox(NULL, _T("Couldn't open service manager"), szServiceName, MB_OK);return FALSE;}//获取程序目录TCHAR szFilePath[MAX_PATH];::GetModuleFileName(NULL, szFilePath, MAX_PATH);//创建服务 SC_HANDLE hService = ::CreateService(hSCM, szServiceName, szServiceName,SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,szFilePath, NULL, NULL, _T(""), NULL, NULL);//检测创建是否成功if (hService == NULL){::CloseServiceHandle(hSCM);MessageBox(NULL, _T("Couldn't create service"), szServiceName, MB_OK);return FALSE;}//释放资源::CloseServiceHandle(hService);::CloseServiceHandle(hSCM);return TRUE;
}//删除服务函数
BOOL Uninstall()
{//检测是否安装过if (!IsInstalled())return TRUE;//打开服务控制管理器SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (hSCM == NULL){MessageBox(NULL, _T("Couldn't open service manager"), szServiceName, MB_OK);return FALSE;}//打开具体服务SC_HANDLE hService = ::OpenService(hSCM, szServiceName, SERVICE_STOP | DELETE);if (hService == NULL){::CloseServiceHandle(hSCM);MessageBox(NULL, _T("Couldn't open service"), szServiceName, MB_OK);return FALSE;}//先停止服务SERVICE_STATUS status;::ControlService(hService, SERVICE_CONTROL_STOP, &status);//删除服务 BOOL bDelete = ::DeleteService(hService);::CloseServiceHandle(hService);::CloseServiceHandle(hSCM);if (bDelete) return TRUE;LogEvent(_T("Service could not be deleted"));return FALSE;
}//记录服务事件
void LogEvent(LPCTSTR pFormat, ...)
{TCHAR chMsg[256];HANDLE hEventSource;LPTSTR lpszStrings[1];va_list pArg;va_start(pArg, pFormat);_vstprintf(chMsg, pFormat, pArg);va_end(pArg);lpszStrings[0] = chMsg;hEventSource = RegisterEventSource(NULL, szServiceName);if (hEventSource != NULL){ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (LPCTSTR*)&lpszStrings[0], NULL);DeregisterEventSource(hEventSource);}
}
编译产物如下:
服务程序本身也是PE格式的文件。
2.2 服务注册
MyService.exe /install
2.3 服务卸载
MyService.exe /uninstall
可以看到服务已经被删除
2.4 启动服务
net start MyService
2.5 关闭服务
net stop MyService
2.6 sc命令
sc命令可以用于管理系统服务、计划任务、系统日志等方面,是不可或缺的神器。
(1) 要查看系统服务列表
sc query state=all
(2) 启动或者停止服务
sc start 服务名
sc stop 服务名
(3) 查看服务属性
例如:以CSV格式输出服务的属性
sc query 服务名 /format:csv
(4) 创建服务
sc create HelloWorldService binPath= "D:\VC\vcDemo\Debug\helloworld.exe"
(5) 山存储服务
sc delete HelloWorldService
实战演示
创建服务
sc create MyService binPath= "D:\VC\vcDemo\Debug\MyService.exe"
启动服务
sc start MyService
关闭服务
sc stop MyService
删除服务
sc delete MyService
2.7 查看服务
方法一
services.msc
方法二:
电脑 - 右键管理
3.标准程序
3.1 后台方式运行标准程序
@ECHO OFF
%1 start mshta vbscript:createobject("wscript.shell").run("""%~0"" ::",0)(window.close)&&exit
start /b helloworld.exe
3.2 查找进程
tasklist | findstr hello
3.3 终止进程
@ECHO OFF
taskkill /im helloworld.exe /f
微软官方关于服务主函数说明:
编写服务程序主函数 - Win32 apps | Microsoft Learn
关于Windows服务,发现一个写的比较好的博客:
C++之创建Windows系统服务_c++编写windows服务-CSDN博客
相关文章:

VC++创建windows服务程序
目录 1.关于windows标准可执行程序和服务程序 2.服务相关整理 2.1 VC编写服务 2.2 服务注册 2.3 服务卸载 2.4 启动服务 2.5 关闭服务 2.6 sc命令 2.7 查看服务 3.标准程序 3.1 后台方式运行标准程序 3.2 查找进程 3.3 终止进程 以前经常在Linux下编写服务器程序…...

连续爆轰发动机
0.什么是爆轰 其反应区前沿为一激波。反应区连同前驱激波称为爆轰波。爆轰波扫过后,反应区介质成为高温高压的爆轰产物。能够发生爆轰的系统可以是气相、液相、固相或气-液、气-固和液-固等混合相组成的系统。通常把液、固相的爆轰系统称为炸药。 19世纪80年代初&a…...

交通物流模型 | 基于时空注意力融合网络的城市轨道交通假期短时客流预测
短时轨道交通客流预测对于交通运营管理非常重要。新兴的深度学习模型有效提高了预测精度。然而,大部分现有模型主要针对常规工作日或周末客流进行预测。由于假期客流的突发性和无规律性,仅有一小部分研究专注于假期客流预测。为此,本文提出一个全新的时空注意力融合网络(ST…...
2.2.1 嵌入式工程师必备软件
1 文件比较工具 在开发过程中,不论是对代码的对比,还是对log的对比,都是必不可不少的,通过对比,我们可以迅速找到差异,定位问题。当前常用的对比工具有:WinMerge,Diffuse,Beyond Compare,Altova DiffDog,AptDiff,Code Compare等。这里推荐使用Beyond Compare,它不…...

深入了解 RabbitMQ:高性能消息中间件
目录 引言:一、RabbitMQ 介绍二、核心概念三、工作原理四、应用场景五、案例实战 引言: 在现代分布式系统中,消息队列成为了实现系统间异步通信、削峰填谷以及解耦组件的重要工具。而RabbitMQ作为一个高效可靠的消息队列解决方案,…...

【数据库——MySQL】(14)过程式对象程序设计——游标、触发器
目录 1. 游标1.1 声明游标1.2 打开游标1.3 读取游标1.4 关闭游标1.5 游标示例 2. 触发器2.1 创建触发器2.2 修改触发器2.3 删除触发器2.4 触发器类型2.5 触发器示例 参考书籍 1. 游标 游标一般和存储过程一起配合使用。 1.1 声明游标 要使用游标,需要用到 DECLAR…...

位移贴图和法线贴图的区别
位移贴图和法线贴图都是用于增强模型表面细节和真实感的纹理贴图技术,但是它们之间也存在着差异。 1、什么是位移贴图 位移贴图:位移贴图通过在模型顶点上定义位移值来改变模型表面的形状。该贴图包含了每个像素的高度值信息,使得模型的细节…...

【typescript】面向对象(下篇),包含接口,属性的封装,泛型
假期第八篇,对于基础的知识点,我感觉自己还是很薄弱的。 趁着假期,再去复习一遍 面向对象:程序中所有的操作都需要通过对象来完成 计算机程序的本质就是对现实事物的抽象,抽象的反义词是具体。比如照片是对一个具体的…...

基于SpringBoot的视频网站系统
目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 视频分享管理 视频排名管理 交流论坛管理 留言板管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 使用旧方法对视频信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运…...

23.3 Bootstrap 框架4
1. 轮播 1.1 轮播样式 在Bootstrap 5中, 创建轮播(Carousel)的相关类名及其介绍: * 1. carousel: 轮播容器的类名, 用于标识一个轮播组件. * 2. slide: 切换图片的过渡和动画效果. * 3. carousel-inner: 轮播项容器的类名, 用于包含轮播项(轮播图底下椭圆点, 轮播的过程可以显…...

ESP32设备驱动-I2C-LCD1602显示屏驱动
I2C-LCD1602显示屏驱动 1、LCD1602介绍 LCD1602液晶显示器是广泛使用的一种字符型液晶显示模块。它是由字符型液晶显示屏(LCD)、控制驱动主电路HD44780及其扩展驱动电路HD44100,以及少量电阻、电容元件和结构件等装配在PCB板上而组成。 通过前面的实例我们知道,并口方式…...
vs工具箱在哪里找
VS工具箱在标题栏 视图->工具箱...

uniapp 事件委托失败 获取不到dataset
问题: v-for 多个span ,绑定点击事件 代码:view里包着一个span, <view class"status-list" tap"search"><span class"status-item" v-for"(key,index) in statusList" :key"index" :data-key"k…...

windows系统下pycharm配置anaconda
参考:超详细的PycharmAnconda安装配置教程_pycharm conda_罅隙的博客-CSDN博客 下载好anaconda安装后,比如我们安装在D盘anaconda文件夹下,在pycharm配置好环境激活时出现问题,可能是电脑没有配置环境变量 需要将一下4行添加到电…...

2023年CSP-J真题详解+分析数据
目录 亲身体验 江苏卷 选择题 阅读程序题 阅读程序(1) 判断题 单选题 阅读程序(2) 判断题 单选题 阅读程序(3) 判断题 单选题 完善程序题 完善程序(1) 完善程序(2) 2023CSP-J江苏卷详解 小结 亲身体验 2023年的CSP-J是在9月16日9:30--11:30进行…...

10.3 调试事件转存进程内存
我们继续延申调试事件的话题,实现进程转存功能,进程转储功能是指通过调试API使获得了目标进程控制权的进程,将目标进程的内存中的数据完整地转存到本地磁盘上,对于加壳软件,通常会通过加密、压缩等手段来保护其代码和数…...

深度学习实战基础案例——卷积神经网络(CNN)基于MobileNetV3的肺炎识别|第3例
文章目录 前言一、数据集介绍二、前期工作三、数据集读取四、构建CA注意力模块五、构建模型六、开始训练 前言 Google公司继MobileNetV2之后,在2019年发表了它的改进版本MobileNetV3。而MobileNetV3共有两个版本,分别是MobileNetV3-Large和MobileNetV2-…...
机器学习 面试/笔试题(更新中)
1. 生成模型 VS 判别模型 生成模型: 由数据学得联合概率分布函数 P ( X , Y ) P(X,Y) P(X,Y),求出条件概率分布 P ( Y ∣ X ) P(Y|X) P(Y∣X)的预测模型。 朴素贝叶斯、隐马尔可夫模型、高斯混合模型、文档主题生成模型(LDA)、限制玻尔兹曼机…...
【算法题】100019. 将数组分割成最多数目的子数组
插: 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 坚持不懈,越努力越幸运,大家一起学习鸭~~~ 题目: 给你一个只包含 非负 整数的数组 n…...
commons-io工具类常用方法
commons-io是Apache Commons项目的一个模块,提供了一系列处理I/O(输入/输出)操作的工具类和方法。它旨在简化Java I/O编程,并提供更多的功能和便利性。 读取文件内容为字符串 String path"C:\\Users\\zhang\\Desktop\\myyii\…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...