修改服务启动后失败重启设置

ChangeServiceConfig2

 SERVICE_FAILURE_ACTIONS sdBuf={0};BOOL bSuccess=TRUE;if (argc!=2){return 1;}// Open a handle to the service. SC_HANDLE sch=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);if (sch==NULL){return 1;}SC_HANDLE schService = OpenService( sch,           // SCManager database argv[1],    // name of service SC_MANAGER_ALL_ACCESS); // need CHANGE accessif (schService == NULL) {printf("OpenService failed (%d)\n", GetLastError()); return FALSE;}sdBuf.lpRebootMsg=NULL;sdBuf.dwResetPeriod=3600*24;        //重新应用的事件间隔,1天SC_ACTION action[3];action[0].Delay=60*1000;          //第一次失败后的等待时间,1分钟action[0].Type=SC_ACTION_RESTART;  //失败后重启action[1].Delay=0;action[1].Type=SC_ACTION_NONE;       //失败后无动作action[2].Delay=0;action[2].Type=SC_ACTION_NONE;sdBuf.cActions=3;sdBuf.lpsaActions=action;sdBuf.lpCommand=NULL;if( !ChangeServiceConfig2(schService,                 SERVICE_CONFIG_FAILURE_ACTIONS, &sdBuf) )                   {printf("%s ChangeServiceConfig2 failed\n",argv[1]);bSuccess = FALSE;}elseprintf("%s ChangeServiceConfig2 succeeded\n",argv[1]);CloseServiceHandle(schService);

服务相关(非代码)

  1. 本机查看服务:services.msc /s 或 手动启动 计算机–>管理–>服务和应用程序–>服务
  2. 手动安装/卸载服务
    安装:sc create 服务名 binpath=服务调用的进程全路径
    卸载:sc delete 服务名
  3. 服务的界面。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服务,需要关机重启,服务才能被清除。
  4. 如果CreateProcessAsUser API使用了参数CREATE_NEW_CONSOLE,那么从Process Explorer就不会看到服务进程跟被启动进程的关联关系。

MSDN阅读

【本段落转自:https://www.cnblogs.com/cswuyg/p/3389948.html】

服务入口点

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发给它的),调用它对应的处理函数(主意:这相当于主线程“陷入”了,它在等待控制消息并对消息做处理)。
服务主函数

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。

【Windows】服务程序相关推荐

  1. 用Visual C#创建Windows服务程序

    一.Windows服务介绍: Windows服务以前被称作NT服务,是一些运行在Windows NT.Windows 2000和Windows XP等操作系统下用户环境以外的程序.在以前,编写Wind ...

  2. c语言编写系统服务程序,C语言Windows服务程序编写-ServiceMain

    C语言编写的Windows服务程序,可以类比Linux/Unix环境下的daemon进程. 一下是VS2010环境下的demo: // windows_service.cpp : 定义控制台应用程序的 ...

  3. C#Windows服务程序安装常见问题解决方法

    C#Windows服务程序安装是如何的呢?让我们开始吧: C#Windows服务程序安装1. 在服务程序的是设计窗体中,点击右键"添加安装程序",添加服务安装程序.否则,安装时会出 ...

  4. Visual C#创建Windows服务程序

    转自:http://www.vchome.net/dotnet/dotnetdocs/dotnet38.htm 一.Windows服务介绍: Windows服务以前被称作NT服务,是一些运行在Wind ...

  5. 编写一个Windows服务程序,定时从数据库中拿出记录发送邮件

    前言:编写一个Windows服务程序,定时从数据库中拿出记录发送邮件. 测试环境:Visual Studio 2005 SP1.Windows Server 2003 SP2 一.新建项目 打开VS2 ...

  6. Windows服务程序时钟调用

    1       大概思路 设计服务程序 创建服务 安装必备组件 编写Service1 运行效果 2       设计服务程序 创建服务程序,通过添加System.Timers时钟进行定时向Wecome ...

  7. C语言编写Windows服务程序

    C语言编写Windows服务程序 原文:C语言编写Windows服务程序 #include <Windows.h> #include <stdio.h>#define SLEE ...

  8. Windows 服务程序编写

    摘要:几乎所有的操作系统在启动的时候都会启动一些不需要与用户交互的进程,这些进程在Windows中就被称作服务.它由服务程序.服务控制程序(SCP,service control program)和服 ...

  9. 多线程、方便扩展的Windows服务程序

    多线程.方便扩展的Windows服务程序 吴剑 2012-06-02 原创文章,转载必需注明出处:http://www.cnblogs.com/wu-jian/ 前言 在项目应用中经常会碰到定时调度的 ...

  10. idea创建三种应用程序的方法:springboot,控制台程序,windows服务程序

    springboot项目 控制台程序 windows服务程序 环境:idea 2017 + Maven 3.3.9+jdk 1.8 一.springboot项目 创建过程依次如下图所示: 至此一个简单 ...

最新文章

  1. 百万奖金悬赏AI垃圾分类,就问你来不来?
  2. js 对象转json,json转对象
  3. session和cookie的应用场景和区别
  4. 使用SHA256证书进行微软数字签名代码签名
  5. 【功率控制】无线光通信-CDMA中闭环链路的功率控制MATLAB仿真
  6. python如何使用ppip安装xlwt_Python中xlrd和xlwt模块使用方法 (python对excel文件的操作)...
  7. C++回调函数是什么?
  8. mysql与mssql中datetime类型字段问题_excel数据存入sqlserver过程中,遇到Datetime的格式问题。...
  9. 这个工具秒杀市面上各种可视化,可惜90%的人都没用过!
  10. OpecCV颜色分割
  11. centos7 使用sendmail 发送邮件
  12. Windows 操作小技巧 之一(持续更新)
  13. 吴恩达新公司曝光:签下富士康,要用AI变革制造业
  14. Discuz!NT v1.0 正式版发布
  15. Gxemul 运行原理简述
  16. cass坡度土方计算案例_南方cass几种土石方计算方法分析.doc
  17. java操作word的方法(总结)
  18. Android常用第三方支付
  19. 【Python】《Python语言程序设计》(嵩天 、黄天羽 、礼欣)测验单项选择题答案与解析合辑
  20. MobaXterm连接虚拟机Ubuntu

热门文章

  1. oracle查询同一天生日的,数据分析经典问题:两个朋友同一天过生日的概率?
  2. 本地pycharm连接到远程服务器(超级详细)
  3. element-ui弹出层置于遮罩层下面问题
  4. js多文件下载和多文件分文件夹打包下载并重命名
  5. 蓝桥杯-第九届决赛——采油
  6. HP LoadRunner
  7. 4月22日丨【云数据库技术沙龙】技术进化,让数据更智能
  8. 简洁的安卓软件下载页源码
  9. 新版一年级上册数学期末试卷
  10. composer更换镜像源