1、本机服务查看:services.msc /s
2、服务手动安装(使用sc.exe):
sc create MemoryStatus binpath= c:\MyServices\MemoryStatus.exe
sc delete MemoryStatus
3、把服务所在进程杀掉,服务也就停止了。
4、服务删除,错误信息:
D:\>sc delete Sample_Srv
[SC] DeleteService FAILED 1072
D:\>sc stop Sample_srv
[SC] ControlService FAILED 1052
解决:service中不能有MessageBox这样的UI框,对话框是不会弹出来的,但是程序会被阻塞,导致无法Stop、无法Delete服务,需要关机重启,服务才能被清除。另外,如果服务启动的进程是没有界面的,那么这个新进程的功能仍然是可以执行的。
5、如何使用DebugView调试
需要在Capture中选中Capture Global Win32
6、服务的界面。Interactive Services
最便捷的方式是使用 WTSSendMessage API 弹出一个对话框,无需任何额外工作。
如果是直接的 MessageBox API,或者是WinExec直接新启动一个GUI进程,需要在CreateService的时候Service类型参数带上SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS参数。但是,win7下任何UI都会导致显示“交互式服务检测”对话框。网络上的那段”打开用户的winsta0”而没有使用CreateProcessAsUser API 的代码在win7下一样有显示“交互服务监测”对话框的问题,是不靠谱的,估计是xp下的杰作。这个弹窗的问题是可以解决的,MSDN上给了解决方案——使用CreateProcessAsUser API 新启动一个进程做界面,服务进程跟界面进程可以使用命名管道做进程间通信。
如果没有设置上面说到的参数,则服务在启动子进程或者是孙进程的整个过程中,不能出现任何界面,不然服务就死了,而且还无法Stop、无法Delete服务,需要关机重启,服务才能被清除。
7、如果CreateProcessAsUser API使用了参数CREATE_NEW_CONSOLE,那么从Process Explorer就不会看到服务进程跟被启动进程的关联关系。
8、通过WTSSendMessage api显示对话框。
DWORD resp = 0;
WTSSendMessage(
WTS_CURRENT_SERVER_HANDLE, 
WTSGetActiveConsoleSessionId(),
"Hello", 5, 
"Hello_2", 7, 
0, 0, &resp, false);
9、一个完善的例子,包括服务程序和界面程序,以及它们之间的通信。但是有些代码无法编译,看看思路就好。
Interaction between services and applications at user level in Windows Vista
http://www.codeproject.com/Articles/36581/Interaction-between-services-and-applications
10、非常完善的从服务启动GUI进程。
NT Services 2013

http://www.codeproject.com/Articles/640245/NT-Services-2013 
10、服务开机启动:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681957(v=vs.85).aspx
11、Sessions,Desktops and Windows Stations
http://blogs.technet.com/b/askperf/archive/2007/07/24/sessions-desktops-and-windows-stations.aspx
12、一个相当简单的服务程序:http://www.vckbase.com/index.php/wv/1193
13、一个包含了安装服务程序、服务程序的完整例子:http://blog.csdn.net/itcastcpp/article/details/7079574 (代码似乎是来自windows核心编程,或者是来自这里:http://bbs.pediy.com/showthread.php?t=114122)
14、一个监控子进程的服务,如果子进程有界面,则会显示出win7下的弹窗,这例子不太好,代码逻辑简单看看就行。
http://www.codeproject.com/Articles/16488/A-Windows-Service-Application

二、MSDN阅读

http://msdn.microsoft.com/en-us/library/ms685477(v=vs.85).aspx
服务入口点
服务程序一般写成控制台应用程序,main函数为入口函数,main函数的参数在CreateService函数中指定。当SCM启动一个服务程序时,SCM等待服务程序调用StartServiceCtrlDispatcher函数,如果服务进程没有及时调用该函数,则会导致启动服务失败(譬如,手动启动时,StartService函数失败)。对于StartServiceCtrlDispatcher函数调用的时机,有下面的规则:
1、如果服务程序是SERVICE_WIN32_OWN_PROCESS类型,服务程序必须在主线程立即调用StartServiceCtrlDispatcher,初始化的工作可以在服务启动之后做,也就是在服务主函数中做。
2、如果服务程序是SERVICE_WIN32_SHARE_PROCESS类型,并且初始化是属于本程序中所有的服务共有的,则可以在调用StartServiceCtrlDispatcher之前执行,但是最多只能执行30秒。可以考虑启动一个新线程去做公共的初始化任务。如果有服务独自的初始化任务,仍然需要在服务启动后在服务主函数中做。
StartServiceCtrlDispatcher函数的参数是SERVICE_TABLE_ENTRY结构体数组,结构体包含了:1、服务名称,这个名称只是在服务主函数中用上,如果服务是SERVICE_WIN32_OWN_PROCESS类型的,那么这个名称是可以忽略的;2、服务主函数指针。
如果StartServiceCtrlDispatcher函数执行成功,调用线程(也就是服务进程的主线程)不会返回,直到所有的服务进入到SERVICE_STOPPED状态。调用线程扮演着控制分发的角色,干这样的事情:1、在新的服务启动时启动新线程去调用服务主函数(主意:服务的任务是在新线程中做的);2、当服务有请求时(注意:请求是由SCM发给它的),调用它对应的处理函数(主意:这相当于主线程“陷入”了,它在等待控制消息并对消息做处理)。
demo代码所在:http://msdn.microsoft.com/en-us/library/windows/desktop/ms687416(v=vs.85).aspx

http://msdn.microsoft.com/en-us/library/ms685984(v=vs.85).aspx
服务主函数
当服务控制程序启动一个新的服务时,服务控制管理器(SCM)启动服务进程,然后服务进程发送开始请求到控制分配器,控制分配器创建一个新的线程去执行服务主函数。服务主函数需要做这样的事情:
1、初始化所有全局变量
2、调用RegisterServiceCtrlHandler API去注册服务的控制请求处理函数,函数的返回值是服务状态句柄,在通知SCM当前服务的状态时用上。
3、完成初始化。如果初始化时间很短(小于1秒),那么初始化可以直接在服务主函数中执行。否则,应该选择下边的一种方式做:
(1)调用SetServiceStatus API把服务状态设置为SERVICE_RUNNING,同时SERVICE_STATUS结构体中的dwControlsAccepted要设置为0,保证在初始化期间SCM不会发送控制请求给本服务,也让SCM可以去管理其他服务。推荐这种方式,以便提高性能,特别是自动运行服务。
(2)调用SetServiceStatus API把服务状态设置为SERVICE_START_PENDING,这时候不会接收控制请求,并且定义了一个超时时间。如果服务的初始化时间超过了预定义的等待时间,那么必须周期性的调用SetServiceStatus API重新定义超时时间,但要确保初始化确实是有进度的,因为此时SCM认为初始化是有进度的,它会阻塞其他服务的开启。如果超时了,而等待的进度信息未改变,SCM或者服务控制程序(可以是自己写的启动服务的程序)会认为发生了错误而需要终止服务(但是如果该服务与其他服务共享进程,则不会结束该服务所在进程)。使用这种方式初始化,可以根据实际进度周期性的调用SetServiceStatus API增加“检查点”的值,服务的启动者可以通过QueryServiceStatus或者QueryServiceStatusEx API去获得检查点的值,也就获得了服务初始化进度。
4、当初始化完成时,调用SetServiceStatus API进入到SERVICE_RUNNING状态、可以接收控制请求。
5、执行服务任务。如果当前没有任务(也就是服务主函数执行完了),控制权还给了调用者(也就是control dispatcher)。如果是单个服务调用 StartServiceCtrlDispatcher,服务主函数执行完了, StartServiceCtrlDispatcher还是不会返回的,要直到服务进入停止SERVICE_STOPPED状态才返回,进程才结束。一般情况下我们不会让出控制权,可以写个死循环去干活,反正主线程退出时会把服务主函数所在线程也结束掉的。另外,任何服务状态的改变都是通过SetServiceStatus做的。
6、如果在服务初始化、执行任务的过程中出现错误,服务在最后一个要被结束的线程中进入SERVICE_STOPPED状态,如果结束服务的清理工作时间很长,则需要进入 SERVICE_STOP_PENDDING状态,执行清理工作。可以通过SERVICE_STATUS结构体的dwServiceSpecificExitCode和dwWin32ExitCode参数告知外界错误信息。
demo代码所在:http://msdn.microsoft.com/en-us/library/windows/desktop/ms687414(v=vs.85).aspx

http://msdn.microsoft.com/en-us/library/ms685149(v=vs.85).aspx
服务控制处理函数
每一个服务都有一个控制处理函数,当服务进程收到控制请求时,由控制分发器调用该函数,所以这个函数的是在控制分发器线程中执行的,也就是服务进程的主线程。当服务控制处理函数被调用时,可以通过SetServiceStatus API把服务设置进不同的状态(也就是通知SCM当前服务是什么状态)。
外界可以通过ControlService API 发送控制请求。所有的服务必须接收并处理SERVICE_CONTROL_INTERROGATE 控制码,可以通过SetServiceStatus API 设置接收哪些控制码,如果要接收SERVICE_CONTROL_DEVICEEVENT控制码,必须调用RegisterDeviceNotification API,服务也能接收用户自定义的控制码。
控制处理函数必须在30秒内返回(但是实际上我测试了Sleep40秒返回也不会导致SCM停止),当有长时间任务时,必须开始新线程去执行。譬如在停止的时候,应该让服务进入到SERVICE_STOP_PENDDING状态,开启新线程执行任务,让服务控制处理函数立即返回。
当系统关闭时,如果有设置了SERVICE_ACCEPT_PRESHUTDOWN,则控制处理函数能收到SERVICE_CONTROL_PRESHUTDOWN 控制码。SCM会等待所有服务停止,或者等待时间超过关机前通知超时值,超时值可以通过ChangeServiceConfig2 API 去设置。这个控制码使用时需要谨慎,避免阻塞关机。
在关机前通知执行完毕之后,所有设置了SERVICE_ACCEPT_SHUTDOWN的服务都能收到SERVICE_CONTROL_SHUTDOWN控制码,通知的顺序是它们安装服务时的顺序。一般情况下,一个服务在关机前有20秒钟的时间处理任务,超时后系统执行关机,无论服务是否完成任务。当系统处于关机状态时,服务仍然是在运行的。
如果一个服务需要更多的时间去做清理工作,它会发送STOP_PENDING状态并设置等待时间。但是,为了防止服务阻止关机,对超时有限制。
在关机期间,SCM发送关机消息时,不会考虑服务之间的依赖关系,所有一个服务可能会因为它所依赖的服务已经停止了而失败。可以手动或者通过API设置服务关闭的依赖关系。
demo代码所在:http://msdn.microsoft.com/en-us/library/windows/desktop/ms687413(v=vs.85).aspx

http://msdn.microsoft.com/en-us/library/ee126211(v=vs.85).aspx
服务状态转换
服务负责向SCM报告状态的改变。服务控制程序和系统只能从SCM获取到服务的状态。服务程序通过SetServiceStatus API设置服务状态。
服务的初始状态是SERVICE_STOPPED,当SCM启动服务后,服务状态进入SERVICE_START_PENDING状态、调用服务主函数,接着服务完成初始化、设置能接受的控制请求,接着通过SetServiceStatus通知SCM进入到SERVICE_RUNNING状态,如果进入的不是SERVICE_RUNNING状态,则SCM、服务监控工具会认为该服务启动失败。
SCM只会发送指定的控制请求给服务(除了SERVICE_CONTROL_INTERROGATE请求,它无需指定)。SERVICE_STATUS结构体的dwControlsAccepted成员指定了哪些控制请求是需求通知服务的。如果要收到设备事件,则需要通过RegisterDeviceNotification API设置。
通常是响应控制请求而去改变服务状态。会引起服务状态改变的控制请求包括:SERVICE_CONTROL_STOP、SERVICE_CONTROL_PAUSE、SERVICE_CONTROL_CONTINUE。如果服务响应时间很长,必须创建第二个线程去完成任务同时告诉SCM进入相应的pendding状态,完成任务之后再进入完成状态。为了更好的性能,vista以及之后版本的系统推荐使用thread pool。
服务状态有效转换图:

服务上报给SCM的状态决定了跟SCM的互动(也就是接下来SCM能发给服务的控制请求)。譬如,如果服务告诉SCM它进入了SERVICE_STOP_PENDDING状态,意味着这时候服务正在关闭,接下来服务只能是通知SCM进入SERVICE_STOPPED状态。
控制服务停止demo:http://msdn.microsoft.com/en-us/library/windows/desktop/ms686335(v=vs.85).aspx

http://msdn.microsoft.com/en-us/library/ms685145(v=vs.85).aspx
服务和注册表
服务不能访问HEKY_CURRENT_USER和HKEY_CLASSES_ROOT,应该使用RegOpenCurrentUser和RegOpenUserClassesRoot函数。
简结:
整个服务的流程可以理解为这样子:假设进程只有单个服务,SCM把服务进程拉起来,服务进程的主线程调用服务控制分发函数,这个函数直到服务停止或者服务开启失败才返回。服务控制分发函数启动新线程执行服务主函数,服务主函数会注册控制处理函数,这是个回调函数,由主线程去调用响应外界的通知,控制回调函数里根据通知把服务设置进不同的状态,这也是告诉SCM服务进入了另一个状态。当服务的状态进入到SERVICE_STOPPED状态时,服务控制分发函数返回,主线程结束,进程结束。

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683502(v=vs.85).aspx
交互式服务
一般情况下,服务是一个没有界面的不需要交互的控制台程序。但是,一些服务有时候要求跟使用者有交互。

在vista系统中服务无法直接跟用户交互。

用户与服务间接交互。
在windows支持的所有版本上,可以使用下边的技术实现:
1、使用WTSSendMessage函数给用户显示对话框。
2、创建一个隐藏的GUI应用程序,使用CreateProcessAsUser API使应用程序在可以跟用户交互的环境下运行。GUI程序使用IPC跟服务程序做数据通信,如果通信使用的是命名管道,那么通过提供基于会话ID的管道名,服务能够区分多用户的进程。
使用交互式服务。
默认情况下服务使用不可交互的“窗口站”,无法跟用户交互。但是,一个可交互的服务能够显示用户界面和接收用户输入。
......
这种方式显示的窗口,是会弹窗提示的。没啥用。
最后文档也说了:所有的服务运行在终端服务session 0。因此,如果一个交互服务显示用户界面,只能是那些进入到session 0的用户才能看到,所有在win7下才会显示一个提示框,让用户进入到另一个界面,也就是session 0。

三、总结

注意到,从服务中启动GUI进程这个可以解决win7下程序要求有管理员权限时,UAC弹框的问题。而服务启动GUI进程,主要需要使用CreateProcessAsUser API。无法让服务进程弹出漂亮的窗口,最多只能直接弹出一个MessageBox,如果想要使用服务的高权限来做些事情,又想要有漂亮的用户界面,则可以让UI进程借服务进程干活,UI进程负责与用户交互,这需要涉及进程间通信(IPC),使用命名管道也很容易实现一个demo,这里就不说了。
服务demo代码所在:https://github.com/cswuyg/simple_win/tree/master/my_service_example,包括了:服务进程、服务中启动GUI进程、服务控制进程的代码。

2014.3 补充

1、服务编程:http://msdn.microsoft.com/en-us/library/windows/desktop/ms685969(v=vs.85).aspx
2、一个完整的服务demo:http://msdn.microsoft.com/en-us/library/bb540476(v=vs.85).aspx
3、服务控制回调函数的响应:
必须在Control Handle函数里正确、及时通知SCM本服务状态的改变。
用户通过服务面板将服务设置为某种状态之后,系统通过检查SCM里该服务的状态是否进入用户想要的状态,来确定操作是否有效,所以,对于服务来说,只需要在Control Handle按照通知码修改对应的状态,就行了,服务是否真的停止了,就看我们程序的意愿了。
如果用户操作了“停止”服务,但是我们的程序没有通知SCM本服务状态改变,就会导致出“Windows 无法停止....服务”的窗口,这种情况发生两次之后,服务进程退出。
4、如何修改服务的一些属性,包括Enabled、Disabled、开机运行服务(这个也可以在CreateService的时候设置SERVICE_AUTO_START)、描述信息:http://msdn.microsoft.com/en-us/windows/desktop/ms682006(v=vs.100).aspx
5、 在编写开机运行服务的时候,需要有自己的log,才能定位是哪块没有执行,windows本身也有日志,但信息太少,windows日志所在:命令行运行运行compmgmt.msc,定位到系统工具\事件查看器\Windows日志\系统,可以看到服务启动相关的信息。在我编写的时候,出现过这种服务无法开机启动的错误:“等待 cswuyg_Svc 服务的连接超时(30000 毫秒)”。多次测试之后,发现把服务进程EXE从Debug版换成Release版本就解决,估计是Debug模式下的性能太差,导致service main函数线程无法及时启动(从log看出service main函数没有被执行到)。

 

Windows Services的更多相关文章

  1. 用C#创建Windows服务(Windows Services)

    用C#创建Windows服务(Windows Services) 学习:  第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(W ...

  2. 当程序以Windows Services形式启动时当前路径不对

    当程序以Windows Services形式启动时当前路径不对 @(操作系统)[博客|dotNet] 很多时候我们需要将我们的程序写成利用Windows服务的形式来让它能够自启动.今天遇到一个问题,当 ...

  3. Windows Services Windows Services的操作

    Windows Services的操作 一.服务的创建: 1.新建项目——Windows服务 2.这是每个人都会犯的错误,新建一个项目后,都会按F5(运行),就会出现如下错误: 3.安装服务有很多种方 ...

  4. the service mysql56 was not found in the Windows services的解决办法

    mysql无法启动,无法改变状态-CSDN论坛-CSDN.NET-中国最大的IT技术社区 http://bbs.csdn.net/topics/390943788   具体描述: 关闭,重启mysql ...

  5. Windows Services的1053错误的解决办法之一:修改注册表允许的响应时间

    Error: 'The service did not respond in a timely fashion' (ServicesPipeTimeout) when attempting when ...

  6. Professional C# 6 and .NET Core 1.0 - Chapter 39 Windows Services

    本文内容为转载,供学习研究.如有侵权,请联系作者删除. 转载请注明本文出处:Professional C# 6 and .NET Core 1.0 - Chapter 39 Windows Servi ...

  7. Windows Services(NT)

    本文主要记录什么是Windows Service,及其主要组成?并通过一个列子来创建一个Windows Services,同时,记录几个在查资料碰到的问题. Windows Services全文简称N ...

  8. C# windows服务:创建Windows服务(Windows Services)的一般步骤

    C#创建Windows服务(Windows Services) Windows服务在Visual Studio 以前的版本中叫NT服务,在VS.net启用了新的名称.用Visual C# 创建Wind ...

  9. Topshelf + QuartzNet 实现挂载在 WIndows Services 中的定时任务

    直接贴代码了: 首先我们可以把所有的 Job 放到一个单独的 DLL 中,好处是可以共享这些业务 Job.比如我们新建一个 QuartzNetDemo.WinService.Jobs 的类库. 然后, ...

随机推荐

  1. 20145304 《Java程序设计》课程总结

    每周读书笔记链接汇总 第一周读书笔记 第二周读书笔记 第三周读书笔记 第四周读书笔记 第五周读书笔记 第六周读书笔记 第七周读书笔记 第八周读书笔记 第九周读书笔记 第十周读书笔记 实验报告链接汇总 ...

  2. Android ListView item项 显示动画

    (1)使用LayoutAnimation 所谓的布局动画,其实就是为ViewGroup添加显示动画效果,主要用过LayoutAnimationController来控制实现.LayoutAnimati ...

  3. NOIp 2013 #2 花匠 Label:爆0的Water

    题目描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定 把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希 望剩下的花排列得比较别致. 具 ...

  4. 【Oracle】如何导库

    正常倒库: 步骤一:在需要导入的库里建立一个新的数据库用户 create user sms533 identified by sms533; grant dba,create session to s ...

  5. bug:clang: error: no input files

    1.clang: error: no input files这个问题一般是因为你删除或者移动了某一个文件,但是在你的编译资源里面( project > target > Build Pha ...

  6. weblogic 11g 配置db2数据源

    配置db2数据源可以直接在包里面配置,不需要专门在服务器上配置数据源. 在11g版本前要配置db2数据源是需要增加包,后续的版本处理了这个问题. 1. 将C:\Program Files\SQLLIB ...

  7. 常用SQL语句(工作)

    1. 经销商 按店铺交易量汇总 ) from bp_shop_info i left join ( select t.shop_id,sum(t.shop_cost) as summary from ...

  8. python基础学习——第二天

    一.python种类 1.1 Cpython python官方版本,使用c语言实现,运行机制:先编译,py(源码文件)->pyc(字节码文件),最终执行时先将字节码转换成机器码,然后交给cpu执 ...

  9. 素数环 Primg Ring Problem

    素数环 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=84562#problem/C 题意: 输入正整数n,把整数1~n组成一个 ...

  10. 浅析-博客Ping服务

    简介:PING服务是博客站点向博客目标网站.搜索引擎等发出的博客内容更新通知服务,然后博客目标网站.搜索引擎就会及时的索引.收录以及传播您的博客内容. PING原理 PING 服务是博客站点向博客目标 ...