编写有图形界面的 Windows 服务程序

YOYOPlayer:基于Java的多功能音乐播放器 音频文件格式可以分为无损压缩、有损压缩以及未压缩(原始数据)三种类型。常见的无损压缩格式有FLAC、ALAC等,它们能够提供高保真的音频体验,而不会丢失任何信息。相比之下,有损压缩格式如MP3和AAC,虽然在文件大小上更为经济,但牺牲了一定的音质以达到更高的压缩比。未压缩的音频文件通常以PCM(Pulse Code Modulation)格式存储,广泛用于音频编辑和母带制作。 阅读详情

下载源代码

环境:Windows 2003,VC 6.0

摘要:从建立一个COM服务程序入手,然后将一个MFC项目改造成服务程序,最后让这一程序在启动时可以显示图形界面。

关键字:windows服务程序 COM服务程序 开机前启动 NT服务 与桌面交互

一、什么是windows的服务程序?

可以使用下面的几种方法看到它。

  1. 打开控制面板,然后是管理工具,里面有一个“服务”,双击后打开;
  2. 或者是通过输入命令的方式,打开开始菜单,点击运行,输入mmc services.msc(mmc可省略),也可打开;

  我们会在打开的页面中看到一个大的列表,标题栏上包含有名称、描述、状态、启动类型、登录身份等项。其中在状态一栏中显示为“已启动”的是系统中已经启动了的服务。我们先看一下服务的属性。举个例子,找到Print Spooler这一名称,然后用右键在上面点击,选择“属性”,可以看到它所执行的命令行是C:/WINDOWS/system32/spoolsv.exe,按下停止后,任务管理器中spoolsv.exe进程退出。我们所见到的这个列表就是服务程序的集中地,每一项就是一个服务程序。

上面这些标为自启动的服务程序随系统一起启动。它与一些修改注册表:

HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Run 

项,及类似注册表项的程序不同的是,即使用户没有登录到系统中,它们也是会运行的,或者说它们在系统登录前运行。

二、怎么建立自己的服务程序?

  每一个服务程序对应注册表项HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services下的一个子项。因此我们可以通过增加注册表项的方式增加服务程序。比如,我现在要增加一个test1服务程序,对应的可执行文件是c:/test1.exe。那么我要增加如下注册表项:

  1. [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/]下增加子项test1;
  2. test1下增加:
    字符串型:"Description"="测试服务1"
    字符串型:"DisplayName"="test1-displayname"
    DWORD型:"ErrorControl"=dword:00000001
    可扩充字符串值(即文件所在路径):
    "ImagePath"=hex(2):43,00,3a,00,5c,00,74,00,65,00,73,00,74,00,31,00,2e,00,65,00,/
    78,00,65,00,00,00
    字符串型:"ObjectName"="LocalSystem"
    DWORD型,值为3表示是手动:"Start"=dword:00000003
    DWORD型:"Type"=dword:00000020
  3. test1下增加子项:
    [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/test1/Security]
    里面的键值从其他的服务程序注册表值中复制。

  如果test1这一程序只是一个普通的win32程序,那么这样做了之后还是不行,服务程序有它自己的一些结构特点。那么怎么编写这些服务程序?
  建立一个服务程序的最简单的方法是用VC中的ATL COM向导。主菜单中选择新建,然后选Projects中的ATL COM AppWizard,输入一个项目名,选择了所在目录后,点OK按钮,在出现的对话框中选择Service(EXE),点Finish即可。然后编译生成test1.exe。
  运行test1.exe /regserver可以注册程序为服务,test1.exe /unregserver是取消注册。test1.exe运行时的参数是在:
Project->Settings->Debug->Program arguments中设置。

三、怎么在建立的服务程序中加入自己的代码?

我们看一下刚才生成的test1项目的结构。

  我们看到test1有一个类CServiceModule和一些Globals的内容。Globals包括一个_tWinMain函数,也就是程序的入口,其中使用了FindOneOf这一与分析命令行有关的函数,还剩下一个全局变量_Module。
  _tWinMain函数中,_Module初始化并设置m_bService为TRUE,在一些分析命令行和判断是否为服务的代码之后,使用_Module.Start()进入主要的执行部分。CServiceModule::Start()中,结构体SERVICE_TABLE_ENTRY建立了服务名与相应处理函数的映射。在这里,如果m_bService为TRUE,则调用StartServiceCtrlDispatcher进入一种类似win32程序的消息处理的过程,用SERVICE_TABLE_ENTRY中的处理函数让程序执行下去。如果m_bService不为TRUE,则直接执行Run()函数。
  在SERVICE_TABLE_ENTRY中,我们看到服务处理函数为_ServiceMain,继续跟踪下去,发现是ServiceMain函数。在ServiceMain中又调用RegisterServiceCtrlHandler为服务增加了一个_Handler函数。对服务程序来说,我们可以在前面打开的服务列表中对它们进行“启动”,“停止”,“暂停”,“恢复”等操作。这实际上是由_Handler来处理不同的信号。_Handler内部调用Handler,在Handler中,对传入的dwOpcode参数作出处理。比如如果是SERVICE_CONTROL_STOP,也就是我们“停止”服务时,将使用PostThreadMessage对主线程发出一个退出的信号。回到ServiceMain函数,在里面同样是在调用Run()函数。也就是说程序以服务身份和非服务身份运行时,区别在于以服务身份运行时多了一个Handler函数,处理用户对服务程序发出的一些信号。
  需要注意的是,这个程序注册为服务时并不是直接写注册表,而是在Install中使用了OpenSCManager,CreateService等函数来完成的任务。显然,这比直接写注册表要好一些,因为有时候我们并不太清楚要怎么去修改注册表项的值来适应不同的服务程序配置,而这些函数有参数可以做到。

说到这里,就涉及到我们自己编写的代码了。
比如现在我们已经建立了一个MFC的程序,想让它成为一个服务程序,那要怎么做呢?
我现在建立一个MFC EXE的项目mfc1,基于对话框。那么把它变为一个服务程序的最简单的方法就是把CServiceModule给拿过来使用。因为我们已经看到CServiceModule类已经把安装服务,卸载服务,运行服务这些操作封装得很好。
打开test1的stdafx.h文件,复制CServiceModule的声明及相关头文件和变量到mfc1的stdafx.h中。
然后是把test1的test1.cpp中对CServiceModule类的实现,复制到mfc1中的mfc1.cpp中。
在stdafx.h中CServiceModule类声明前加上#include <winsvc.h>,它里面是对结构体SERVICE_STATUS_HANDLE的声明。
编译后出现以下类似错误:

D:/vc6_test/mfc1/mfc1.cpp(52) : error C2065: ''IDR_Test1'' : undeclared identifier
D:/vc6_test/mfc1/mfc1.cpp(336) : error C2065: ''CoInitializeSecurity'' : undeclared identifier
D:/vc6_test/mfc1/mfc1.cpp(337) : error C2065: ''EOAC_NONE'' : undeclared identifier
D:/vc6_test/mfc1/mfc1.cpp(362) : error C2065: ''IDS_SERVICENAME'' : undeclared identifier
D:/vc6_test/mfc1/mfc1.cpp(362) : error C2065: ''LIBID_TEST1Lib'' : undeclared identifier

  我们可以在test1中找到IDR_Test1的声明,放到mfc1中,解决第一条错误。但我们也可以去掉CServiceModule中与COM有关的一些代码。这里我们删除RegisterServer,UnregisterServer两个函数,并让Run函数成为

void CServiceModule::Run()
{
    _Module.dwThreadID = GetCurrentThreadId();
    LogEvent(_T("Service started"));
    if (m_bService)
        SetServiceStatus(SERVICE_RUNNING);

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
        DispatchMessage(&msg);
}		
增加资源IDS_SERVICENAME为“mfc1”。
注释掉CServiceModule::Init中“CComModule::Init(p, h, plibid);”一行。
注释_tWinMain函数(技巧:用#if 0和#endif注释)。

现在编译程序,应该没有错误了,但加入的CServiceModule还没有起到作用。

在mfc1中的IDD_MFC1_DIALOG上加入两个按钮,分别是“安装服务”,“卸载服务”。增加的单击事件代码为:
“安装服务”按钮:void CMfc1Dlg::OnButton1() { _Module.Install(); }
“卸载服务”按钮:void CMfc1Dlg::OnButton2() { _Module.Uninstall(); }

下面在CMfc1App::InitInstance()中加入一些代码:

_Module.Init(ObjectMap, this->m_hInstance, IDS_SERVICENAME, NULL);
_Module.m_bService = TRUE;
_Module.Start();

  地点是在原来产生对话框的代码的地方。而原有的生成对话框的代码转移到Run()中,位置是在使用了SetServiceStatus函数设置服务状态之后,并注释掉其后的消息处理代码,因对话框自身有消息处理机制。

编译时若出现如下错误,将Install()和Uninstall()前的inline参数去掉即可:

mfc1Dlg.obj : error LNK2001: unresolved external symbol "public: int __thiscall CServiceModule::Install(void)" (?Install@CServiceModule@@QAEHXZ)

mfc1Dlg.obj : error LNK2001: unresolved external symbol "public: int __thiscall CServiceModule::Uninstall(void)" (?Uninstall@CServiceModule@@QAEHXZ)

现在可以编译运行了。然后点击“安装服务”,就可以在服务列表中看到mfc1了。

四、这一服务程序运行时没有图形界面?

  不错,刚才直接运行mfc1.exe时我们看到了图形界面,但在服务列表中用右键菜单中的“启动”时却看不到任何界面。这该怎么办?
我们还需要在使用CreateService函数时(Install()中),加上一个参数,这样才能允许程序与桌面交互,也就是可以显示界面。这个参数是SERVICE_INTERACTIVE_PROCESS。
填加后的CreateService:

    SC_HANDLE hService = ::CreateService(
        hSCM, m_szServiceName, m_szServiceName,
        SERVICE_ALL_ACCESS, 
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
        SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
        szFilePath, NULL, NULL, _T("RPCSS/0"), NULL, NULL);		
再次编译mfc1,卸载服务后,安装服务。我们可以看到,通过服务列表启动mfc1,原有的对话框出现了。

如需将服务设为自动启动,则将 SERVICE_DEMAND_START 改为 SERVICE_AUTO_START。 
Simulink仿真模块-Signal Generator Signal Generator:生成各种波形 所在的位置库为:Simulink / Sources 模型为: 说明 Signal Generator模块可以产生四种不同波形: 正弦波 方波 锯齿波 随机 可以使用 hertz 或 rad/sec 为单位表示信号参数。双击模型可以选择需要生成的波形,如图所示: 使用默认参数值,可以获得下列波形之一: 波形 波形输出 正弦波 ... 阅读详情

相关推荐

StarCCM+ 导入STL几何模型进行仿真

通过 Import Surface Mesh 的方法导入 STL 文件进行仿真

薛定谔的alpha狗 6129

Windows添加自定义服务

【代码】Windows添加自定义服务。

qq_40679799的博客 456

在摩尔线程 MTT S80 上使用 Ollama 进行 DeepSeek R1 蒸馏版模型推理

本文主要介绍了如何在摩尔线程 MTT S80 上通过 Ollama 快速完成DeepSeek R1 蒸馏系列模型的推理。

摩尔线程blog中心 3599

创建自定义的服务Windows NT service

创建自定义的Windows NT service

wsdhla的专栏 5638

【开源】STM32+ESP8266+MQTT多传感器数据上云OneNET(易拓展,带操作系统FreeRTOS)

【开源】STM32+ESP8266+MQTT多传感器数据上云OneNET(易拓展) 文章目录【开源】STM32+ESP8266+MQTT多传感器数据上云OneNET(易拓展)1. 相关连接1.1 本项目相关连接1.2 无操作系统简易版(旧版,有OneNET云平台设备创建和应用配置,本文不再赘述):2. 具体功能3. 硬件环境4. 云平台环境配置5. 接线6. 功能展示6.1 数据流6.2 APP应用管理6.3 串口数据7. 源码详解7.1 源码文件解析7.2 服务器与wifi配置相关7.3 源码框架7.4

ssssadw的博客 2万+

10-142 6-4 查询厂商“D“生产的PC和便携式电脑的平均价格

分数 10全屏浏览题目切换布局作者 lhm单位 河北农业大学本题目要求编写SQL语句,查询厂商D生产的PC和便携式电脑的平均价格。

dqd66的博客 2748

windows下手动创建服务

windows下手动添加Windows服务

nich_olas的博客 2888

ANSYS APDL实战:手把手教你搞定电磁-热耦合分析(附完整命令流)

本文通过一个工业感应加热线圈的实战案例,手把手教你使用ANSYS APDL完成电磁-热耦合分析。内容涵盖从几何建模、材料定义、网格划分到加载求解及后处理的完整流程,重点讲解了使用PLANE13单元进行双向耦合场分析的方法与命令流调试技巧,助力工程师快速掌握这一核心仿真能力。

weixin_29284201的博客 427

Windows子系统安装图形界面

Windows子系统安装图形界面 有很多同学需要使用 linux 系统,但是又不想真正安装一个 linux 系统。于是微软大哥就把 ubuntu 系统集成到 windows 内了,你说 微软 屌不屌? 言归正传。 安装xfce4-terminal 因为这个是最靠谱的图形化界面了,所以不解释。 在win10的应用商店中搜索并安装 Xming XServer for Windows,运行其中的 X...

FlyWine的博客 4358

【Burp入门第三十一篇】Burp+SwitchyOmega实现本地localhost代理

在部分情况下(如本地靶场),当我们需要在Burp中查看、修改本地流量包的时候,按以下三个配置是不能得到本地流量包的。

等风来 3214

YOLO26改进策略【模型轻量化】| 替换骨干网络 CVPR-2024 StarNet,超级精简高效的轻量化模块

本文记录的是。YOLO26主要用于轻量化应用部署,相关轻量化改进与其整体架构非常适配。StarNet设计简洁,没有复杂的设计和精细调整的超参数,仅是一个 4 阶段的分层架构。并且其中能够在低维空间计算的同时考虑极高维的特征这一特性,进而提高模型精度。本文在替换骨干网络中配置了原论文中的starnet_s1starnet_s2starnet_s3和starnet_s4七种模型,以满足不同的需求。

Limiiiing的博客 1091

管理 Windows 自定义服务(Windows Service)

管理 Windows 自定义服务(Windows Service)

前端开发 2112

pycharm报错cannot start the IED:Error occurred during initialization of VMagent library failed...如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 1925

YOYOPlayer(一个开源音乐播放器)

一个java写的类天天静听的开源音乐播放器。 运行主类com.hadeslee.yoyoplayer.player.ui.Main  

suyijianke的博客 683

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

开源JAVA音乐播放器YOYOPlayer1.2发布,全面改进歌词搜索

开源JAVA音乐播放器YOYOPlayer1.2发布,全面改进歌词搜索注意:JRE的最低版本是:1.6本项目的所有代码已移到google code,此前在sourceforge和java.net项目不再维护了,现在项目的地址为:http://code.google.com/p/yoyoplayer在使用过程中有任何问题,都欢迎在此留言。 1.2更新[2009-08-02] 1,全新的歌词搜索方式,使搜索率大大提高。 2,把整个代码全部移到google code上去。以前的sourceforge和java

lemonzone2010的专栏 925

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

YOYOPlayer开源音乐播放器

<br />yoyoplayer的项目: http://sourceforge.net/projects/yoyoplayer <br /> <br />svn地址:https://yoyoplayer.svn.sourceforge.net/svnroot/yoyoplayer <br /> <br /> 

懒虫一个V 4221

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

开源JAVA音乐播放器YOYOPlayer1.1.3发布

注意: 源码可以到https://yoyoplayer.dev.java.net上下载,也可以加入QQ超级群:48052244,在群共享里面也有下载. JRE的最低版本是:1.6 --------------------------------------------------------------------------------- 1.1.3更新[2008-07-28] 1,完全去除了其...

iteye_3373的博客 250

看到一个NB的人: 千里冰封--JAVA 浓香四溢

一个NB的Java程序员,做了一个NB的java音乐播放器Yoyoplayer,他居然还写过几首歌。   千里冰封--JAVA 浓香四溢 http://www.blogjava.net/hadeslee/ google code http://code.google.com/p/yoyoplayer/   JAVA音乐播放器(Netbeans插件版) http://www.blog

victoryckl的专栏 1394

MoMoPlayer,纯java音乐播放器

# MoMoPlayer,纯java音乐播放器 # 致我最爱得人 # github源码  :https://github.com/junehappylove/MoMoPlayer # 修改自千里冰封的YOYOPlayer Version=2.0 URL=https://github.com/junehappylove/MoMoPlayer/releases/tag/MoMoPlaye...

junehappylove(王俊伟)的专栏 283

java播放器使用教程_[Java教程]Java音乐播放器

[Java教程]Java音乐播放器0 2016-01-07 12:00:09乐乐音乐目前是基于musique开发的一个java音乐播放器,之前开发了一个android版本的音乐播放器,现在把android版本的代码移植过来PC版本这里。不过遇到了一个难题,就是java如果要播放mp3等歌曲,要安装jmf,我觉得安装这jmf真是太麻烦了,电脑是64位的伤不起啊。于是我从网上搜了一下,搜...

weixin_39930252的博客 744

感谢开源

     不知不觉中,从学习毕业已经一年半了,在这一年半的工作时间里,大部分的时间都在跟java打交道,无论是编程还是测试。     尽管大学学的不是软件,但这一年半的时间却让我深深地喜欢上了软件,尤其是开源的java。它让我步入了一个伟大而无私的世界,在这个势力的社会中,显得尤其难能可贵。     虽然本人的java水平仍旧处于菜鸟的档次上,但仍然乐忠于学习和宣传它,愿意为之付出辛勤的汗

lybsdu的专栏 806

YOYOPlayer:linux下开源的千千静听

作者:linuxeden团队 mgqw猴子   说到mp3播放软件,眼下最受国人欢迎的非windows下的千千静听莫属,这个软件没什么好说的:好看又好用。相对linux下mp3播放软件,用得最多的应该是xmms吧,这个软件让中国的linuxer又爱又恨:xmms的各项功能还算中规中矩,可它的中文乱码问题一直让广大中国用户看着烦心,前段时间听人家吹嘘说已经彻底解决中文乱码问题

bluewind1982的专栏 1053
上一篇: VC中隐式链接无.LIB动态链接库的方法
下一篇: Windows 文件过滤驱动经验总结
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值