VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 971|回复: 8

[求助] 生成器板块中服务程序的疑惑求解

[复制链接]
08_avatar_middle
online_vip 发表于 2017-3-16 10:06:38 | 显示全部楼层 |阅读模式
int _tmain(int argc, _TCHAR* argv[])
{
        SERVICE_TABLE_ENTRY DispatchTable[]=
        {
                {(TCHAR*)ServiceName,ServiceMain},//服务程序的名称和入口点
                {NULL,NULL}//SERVICE_TABLE_ENTRY结构必须以“NULL”结束
        };

        StartServiceCtrlDispatcher(DispatchTable);
        InstallService();
       
        /*CloseHandle(CreateThread(NULL,0,StartMainThread,NULL,0,NULL));

        while (!m_bStop)
        {
                Sleep(1000);
        }*/

        WSACleanup();
        return 0;
}

如上面代码,1、为什么InstallService();安装服务函数只执行一次?2、我认为应该是这样的:双击Server.exe服务端程序时,InstallService()执行,服务安装完成,以后就不执行InstallService()了?




上一篇:有没有书讲va_list,va_start,va_arg这些,能不能告诉我书名
下一篇:在线求助
76_avatar_middle
在线会员 发表于 2017-3-16 11:01:55 | 显示全部楼层
楼主首先应该理解windows服务的概念。
windows服务程序是windows系统中可执行程序中的比较特殊的一种。
服务程序是没有用户界面的,这样它就可以脱离windows的USER32子系统运行。普通有界面的程序是要依赖用户界面的,即依赖user32子系统,也就是说要windows系统登录出现桌面后才能运行。
服务程序是受windows系统的SCM(服务控制管理器)管理的。一个服务编写好后不能直接双击运行,需要通过控制管理程序启动才可以。这需要先在系统的服务控制管理器数据库中登记。这样SCM才会在每次开机时自动运行服务,或者系统启动后通过SCM手动运行服务。
InstallService()函数就是调用API CreateService()函数在SCM数据库中登记服务的过程。所以说安装服务函数仅需执行一次。
76_avatar_middle
在线会员 发表于 2017-3-16 11:06:12 | 显示全部楼层
int _tmain(int argc, _TCHAR* argv[])
{
        SERVICE_TABLE_ENTRY DispatchTable[]=
        {
                {(TCHAR*)ServiceName,ServiceMain},//服务程序的名称和入口点
                {NULL,NULL}//SERVICE_TABLE_ENTRY结构必须以“NULL”结束
        };

        StartServiceCtrlDispatcher(DispatchTable);
  
        return 0;
}
一个服务的进程应该这样,不要在服务进程中做其他额外的工作,只要填写服务条目,然后启动服务控制派遣,告诉系统那个是服务主函数就可以了
08_avatar_middle
ico_lz  楼主| 发表于 2017-3-16 11:27:45 | 显示全部楼层
jlpanxishuang 发表于 2017-3-16 11:06
int _tmain(int argc, _TCHAR* argv[])
{
        SERVICE_TABLE_ENTRY DispatchTable[]=


int _tmain(int argc, _TCHAR* argv[])
{
        SERVICE_TABLE_ENTRY DispatchTable[]=
        {
                {(TCHAR*)ServiceName,ServiceMain},//服务程序的名称和入口点
                {NULL,NULL}//SERVICE_TABLE_ENTRY结构必须以“NULL”结束
        };

        StartServiceCtrlDispatcher(DispatchTable);
        InstallService();
      

        WSACleanup();
        return 0;
}
说的的确没错。但上述代码是远控班里讲的,把服务的安装也放到了main函数里面,暂且不论这样的写法好坏,就单论上述代码而言,如何保证 InstallService();只运行一次?也就是双击程序的时候,不运行: StartServiceCtrlDispatcher(DispatchTable),只运行 InstallService()来安装服务,等服务安装好后,每次启动服务的时候就不运行 InstallService()函数了?
76_avatar_middle
在线会员 发表于 2017-3-16 12:08:13 | 显示全部楼层
假如程序第一次运行:先调用StartServiceCtrlDispatcher(DispatchTable);调用是失败的,因为没有调用API 函数CreateService()在SCM数据库中建立服务。调用GetLastError()返回的错误代码是:1603L 服务进程不能连接到服务控制器
接着调用InstallService()安装服务,调用成功,服务程序的信息被写入SCM数据库中。

第二次调用:StartServiceCtrlDispatcher(DispatchTable);调用成功,因为服务已经被建立了。这是SCM会启动ServiceMain()回调函数,服务正式运行。
接着调用InstallService(),会失败,因为服务已经安装了。调用GetLastError()函数返回错误代码:1073 指定的服务已存在。
以后每次运行InstallService()都是调用失败的,除非服务被卸载后再运行会成功。
08_avatar_middle
ico_lz  楼主| 发表于 2017-3-17 10:21:36 | 显示全部楼层
jlpanxishuang 发表于 2017-3-16 12:08
假如程序第一次运行:先调用StartServiceCtrlDispatcher(DispatchTable);调用是失败的,因为没有调用API 函 ...

非常感谢,感觉你第一部分说的是对的。针对第二次调用这部分,如果按你说的话服务主线程就退出了。我查到了一篇很不错的资料,是这么说的,分享下:

SCM启动一个服务程序之后,它会等待该程序的主线程去调StartServiceCtrlDispatcher。如果那个函数在两分钟内没有被调用,SCM将会认为这个服务有问题,并调用TerminateProcess去杀死这个进程。这就要求你的主线程要尽可能快的调用StartServiceCtrlDispatcher。

StartServiceCtrlDispatcher函数则并不立即返回,相反它会驻留在一个循环内。当在该循环内时,StartServiceCtrlDispatcher悬挂起自己,等待下面两个事件中的一个发生。第一,如果SCM要去送一个控制通知给运行在这个进程内一个服务的时候,这个线程就会激活。当控制通知到达后,线程激活并调用相应服务的CtrlHandler函数。CtrlHandler函数处理这个服务控制通知,并返回到StartServiceCtrlDispatcher。StartServiceCtrlDispatcher循环回去后再一次悬挂自己。

第二,如果服务线程中的一个服务中止,这个线程也将激活。在这种情况下,该进程将运行在它里面的服务数减一。如果服务数为零,StartServiceCtrlDispatcher就会返回到入口点函数,以便能够执行任何与进程有关的清除工作并结束进程。如果还有服务在运行,哪怕只是一个服务,StartServiceCtrlDispatcher也会继续循环下去,继续等待其它的控制通知或者剩下的服务线程中止。


附上博文地址:http://blog.csdn.net/byxdaz/article/details/8565528
76_avatar_middle
在线会员 发表于 2017-3-17 12:54:58 | 显示全部楼层
楼主我翻译的MSDN文档中的StartServiceCtrlDispatcher 文档,你可以参考下,由于英语水平有限,有很多地方翻译的不是很恰当,见笑了。基本上思想表达的应该使没有问题的。
StartServiceCtrlDispatcher 函数
描述
连接服务进程的主线程到服务控制管理器,使调用此函数进程的主线程成为服务控制派遣线程。
BOOL WINAPI StartServiceCtrlDispatcher(
  __in          const SERVICE_TABLE_ENTRY* lpServiceTable
);
参数
lpServiceTable
指向SERVICE_TABLE_ENTRY结构的指针,此结构中包含每个可被进程调用的服务的一个条目。表中最后一个条目的成员值必须为NULL指明为表的结尾。
返回值
如果函数调用成功,返回非零值。
如果函数调用失败,返回零值。获取扩展错误信息,调用GetLastError()。
下述错误代码可以通过服务控制管理器设置。其他错误代码可以由服务控制管理器调用注册表函数设置。
返回代码        描述
ERROR_FAILED_SERVICE_CONTROLLER_CONNECT        如果此程序作为控制台应用程序而不是服务程序运行,则返回此错误。 如果程序以调试为目的运行为控制台应用程序,则将其构造为:当此错误发生时不调用特定于服务的代码。
ERROR_INVALID_DATA        指定的派遣表包含格式不正确的条目。
ERROR_SERVICE_ALREADY_RUNNING        进程已经调用StartServiceCtrlDispatcher。每个进程仅可以调用 一次StartServiceCtrlDispatcher 。
Windows NT: 不支持此值。
注解
当服务控制管理器启动服务进程时,它等待进程调用StartServiceCtrlDispatcher 函数。服务进程的主线程应该在启动后(30秒内)尽快调用此函数.如果 StartServiceCtrlDispatcher 调用成功,它连接调用线程到服务控制管理器,直到进程中所有的服务进入SERVICE_STOPPED状态。服务控制管理器使用此连接发送控制和服务启动请求给服务进程的主线程。主线程充当调度者,通过调用恰当的HandlerEx 函数处理控制请求;或者当一个新的服务启动时通过建立一个新的线程执行恰当的ServiceMain 函数。
lpServiceTable 参数中包含运行在调用进程中每个服务的条目。每个条目指定服务的ServiceMain()函数。对于SERVICE_WIN32_SHARE_PROCESS 服务,每个条目必须包含服务的名称。这个名称是服务的名称,是在调用CreateService()函数安装服务时指定的。对于SERVICE_WIN32_OWN_PROCESS 服务,服务名称在表条目中是忽略的。
如果服务运行于独享进程,服务进程的主线程将马上调用StartServiceCtrlDispatcher 。所有初始化任务当服务启动后在服务的ServiceMain 函数中进行。
如果多个服务共享一个进程,并且某些通用全过程初始化需要先于任何一个ServiceMain()被调用,主线程可以在调用StartServiceCtrlDispatcher 前进行初始化,只要少于30秒就可以。否则,必须创建另外一个线程进行全过程初始化,直到主线程调用StartServiceCtrlDispatcher 并且成为服务控制调度者。一些特定于服务的初始化仍将在服务主函数ServiceMain()中进行。
服务不应该尝试直接显示一个用户界面。详见Interactive Services。
示例代码
示例, 见 Writing a Service Program's Main Function.
必要条件
客户端        需要 Windows Vista, Windows XP, Windows 2000 Professional, 或 Windows NT Workstation.
服务器        需要 Windows Server 2008, Windows Server 2003, Windows 2000 Server, 或 Windows NT Server.
头文件        声明于 Winsvc.h; 包含 Windows.h.
静态库        使用 Advapi32.lib.
动态链接库        需要 Advapi32.dll.
Unicode        实现为StartServiceCtrlDispatcherW (Unicode) 和 StartServiceCtrlDispatcherA (ANSI).
76_avatar_middle
在线会员 发表于 2017-3-17 12:56:01 | 显示全部楼层
格式不太好,附上word文档

函数 StartServiceCtrlDispatcher .doc

41.5 KB, 下载次数: 2

75_avatar_middle
在线会员 发表于 2018-1-14 18:45:56 | 显示全部楼层
哈哈哈还是a
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号tongdun|网站地图wx_jqr

GMT+8, 2019-4-19 11:29

Powered by Discuz! X3.4

© 2009-2019 cctry.com

快速回复 返回顶部 返回列表