3.1.2 服务应用程序.htm

来自「Windows2000后台服务程序开发手册」· HTM 代码 · 共 559 行 · 第 1/4 页

HTM
559
字号
                <TD></TD></TR></TBODY></TABLE>
            <DIV class=content id=ArticleBody 
            style="PADDING-RIGHT: 10px; DISPLAY: block; PADDING-LEFT: 10px; PADDING-BOTTOM: 0px; PADDING-TOP: 0px">
            <P class=content>
            <TABLE style="LINE-HEIGHT: 25px" border=0>
              <TBODY style="LINE-HEIGHT: 25px">
              <TR style="LINE-HEIGHT: 25px">
                <TD style="LINE-HEIGHT: 25px" align=middle><FONT 
                  style="LINE-HEIGHT: 25px" face=arial color=#000000 
                  size=2><FONT style="LINE-HEIGHT: 25px" face=arial 
                  color=#3e80d7 size=2><B 
                  style="LINE-HEIGHT: 25px">&nbsp;图3-4&nbsp;</B></FONT>Distributed 
                  Link Tracking服务之登入页签内容</FONT></TD></TR></TBODY></TABLE>
            <CENTER></CENTER>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e74d7 
            size=3><B style="LINE-HEIGHT: 25px">修复页签内容<BR 
            style="LINE-HEIGHT: 25px"> </B></FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>如图3-5所示之修复页签内容,它允许管理者告诉SCM当服务发生异常中断情形时,该执行什么动作。异常中断表示该服务没有回报一个SERVICE_STOPPED的状态即停止执行。在第一次、第二次以及后续的尝试执行失败时,SCM可以不执行动作、重新执行服务、执行文件或重新启动电脑。注意到如果执行该服务的帐户没有适当的存取权限或者许可,则在执行文件和重新启动电脑的动作时,该动作的执行会失败。</FONT></P>
            <P><BR style="LINE-HEIGHT: 25px"> </P>
            <CENTER style="LINE-HEIGHT: 25px">
            <P><INPUT id=5 style="LINE-HEIGHT: 25px" type=image height=476 
            width=500 src="3.1.2 服务应用程序.files/3-5.gif" border=0 
            &#111nclick="imgclick"></P></CENTER>
            <CENTER style="LINE-HEIGHT: 25px">
            <TABLE style="LINE-HEIGHT: 25px" border=0>
              <TBODY style="LINE-HEIGHT: 25px">
              <TR style="LINE-HEIGHT: 25px">
                <TD style="LINE-HEIGHT: 25px" align=middle><FONT 
                  style="LINE-HEIGHT: 25px" face=arial color=#000000 
                  size=2><FONT style="LINE-HEIGHT: 25px" face=arial 
                  color=#3e80d7 size=2><B 
                  style="LINE-HEIGHT: 25px">&nbsp;图3-5&nbsp;</B></FONT>Fax 
                  Service服务之修复页签内容</FONT></TD></TR></TBODY></TABLE></CENTER>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e74d7 
            size=3><B style="LINE-HEIGHT: 25px">依存关系页签内容<BR 
            style="LINE-HEIGHT: 25px"> </B></FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>如图3-6所示之依存关系页签说明了被选择的服务依存于何种服务或是什么服务依存于该服务。在图中,您会看到五个服务依存于Workstation服务。假如管理者试图去停止Workstation服务且附属于它的服务正在执行,则SCM会呼叫失败。许多SCP程序会通知使用者该附属服务正在执行,并可让使用者选择哪一个附属的服务要一并停止。依存关系页签不允许管理者修改任何的依存关系(我会在下一章讨论更多有关服务依存关系的内容)。</FONT></P>
            <P><BR style="LINE-HEIGHT: 25px"> </P>
            <CENTER style="LINE-HEIGHT: 25px">
            <P><INPUT id=6 style="LINE-HEIGHT: 25px" type=image height=476 
            width=500 src="3.1.2 服务应用程序.files/3-6.gif" border=0 
            &#111nclick="imgclick"></P></CENTER>
            <CENTER style="LINE-HEIGHT: 25px">
            <TABLE style="LINE-HEIGHT: 25px" border=0>
              <TBODY style="LINE-HEIGHT: 25px">
              <TR style="LINE-HEIGHT: 25px">
                <TD style="LINE-HEIGHT: 25px" align=middle><FONT 
                  style="LINE-HEIGHT: 25px" face=arial color=#000000 
                  size=2><FONT style="LINE-HEIGHT: 25px" face=arial 
                  color=#3e80d7 size=2><B 
                  style="LINE-HEIGHT: 25px">&nbsp;图3-6&nbsp;</B></FONT>Workstation服务之依存关系页签内容</FONT></TD></TR></TBODY></TABLE></CENTER>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7 
            size=4><B style="LINE-HEIGHT: 25px">Net.exe与SC.exe<BR 
            style="LINE-HEIGHT: 25px"> </B></FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>除了服务嵌入式管理单元外,Windows还附了一个称为Net.exe的SCP命令列工具。这个工具限制您只能控制那些存在于本机上的服务。使用Net.exe,您可以使用下列的语法来启动、停止、暂停以及继续执行服务:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">NET START servicename <BR>NET STOP servicename <BR>NET PAUSE servicename <BR>NET CONTINUE servicename</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>您也可以不需指定一个servicename,只需简单地键入以下的指令即可显示正在本机上执行的服务清单:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">NET START</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>您可以将这些呼叫指令放入一个批次档或其他的指令码文件中,所以Net.exe工具非常容易使用在侦错上。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>另一个Microsoft提供的SCP应用程序是一个称做SC.exe的命令列工具程序。这个工具包含在Microsoft 
            Windows 2000 Resource 
            Kit中。当执行这个工具而没有传入任何参数时,它会显示用法与语法,列示如下:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">说明:&nbsp;&nbsp;<BR> SC是一个命令列程序,用在与NT服务控制器及服务沟通上。 <BR>用法: <BR> sc <SERVER> [command] [service name]&nbsp;&nbsp; <OPTION1>&nbsp;&nbsp; <OPTION2>... <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类型、方法、型式 <BR> <SERVER> 选项的型式为 \\ ServerName <BR> 在键入「sc [command]」时可以获得进一步的帮助。 <BR> 命令: <BR>&nbsp;&nbsp;query-----------询问一个服务状态或列举出多个服务类型的状态。&nbsp;&nbsp;<BR>&nbsp;&nbsp;queryex---------询问一个服务的延伸状态或列举出多个服务类型 <BR>&nbsp;&nbsp;的状态。 <BR>&nbsp;&nbsp;start-----------启动一个服务。 <BR>&nbsp;&nbsp;pause-----------传送一个PAUSE控制要求给服务。 <BR>&nbsp;&nbsp;interrogate-----传送一个INTERROGATE控制要求给服务。 <BR>&nbsp;&nbsp;continue--------传送一个CONTINUE控制要求给服务。 <BR>&nbsp;&nbsp;stop------------传送一个STOP要求给服务。 <BR>&nbsp;&nbsp;config----------改变服务的永久设定。 <BR>&nbsp;&nbsp;description-----改变服务的说明。 <BR>&nbsp;&nbsp;failure---------改变服务失败后的动作。 <BR>&nbsp;&nbsp;qc--------------询问服务的说明资讯。 <BR>&nbsp;&nbsp;qdescription----询问服务的内容。 <BR>&nbsp;&nbsp;qfailure--------询问服务失则时所做的动作。 <BR>&nbsp;&nbsp;delete----------从登录中删除服务。 <BR>&nbsp;&nbsp;create----------建立一个服务(新增至登录中)。 <BR>&nbsp;&nbsp;control---------传送一个控制给服务 <BR>&nbsp;&nbsp;sdshow----------显示服务的安全描述。 <BR>&nbsp;&nbsp;sdset-----------设定服务的安全描述。 <BR>&nbsp;&nbsp;GetDisplayName-取得服务的DisplayName。 <BR>&nbsp;&nbsp;GetKeyName------取得服务的ServiceKeyName。 <BR>&nbsp;&nbsp;EnumDepend------列举服务的依存关系。 <BR> 以下的命令不需要提供服务名称: <BR> sc <SERVER> <COMMAND>&nbsp;&nbsp; <OPTION> <BR>&nbsp;&nbsp;boot------------(ok | bad)指出哪一个启动记录应该被储存成 <BR>&nbsp;&nbsp;last-known-good之启动设定。 <BR>&nbsp;&nbsp;Lock------------锁定服务资料库。 <BR>&nbsp;&nbsp;QueryLock-------要求SCManger资料库之LockStatus。 <BR>范例:: <BR> sc start MyService <BR>您想要看有关QUERY与QUERYEX的帮助说明吗? <BR>[ y | n ]: y <BR>QUERY与QUERYEX OPTIONS: <BR> 假如在一个服务名称后跟着query命令,则该服务的状态会被回传。其他的选 <BR> 项在这个情形下不会起任何作用。如果query命令的后面跟随着下面所列的选 <BR> 项之一或是空白,所有服务皆会被列举出来。 <BR> Type= 列举服务的类型(所有的驱动程序、服务)。 <BR>&nbsp;&nbsp;&nbsp;&nbsp;(预设值 = service) <BR> state= 列举服务的状态(所有闲置的) <BR>&nbsp;&nbsp;&nbsp;&nbsp; (预设值 = active) <BR> bufsize= 列举缓冲器的位元组大小。 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(预设值 = 1024) <BR> ri= 开始此列举之恢复索引号码。 <BR>&nbsp;&nbsp; (预设值 = 0) <BR> group= 列举服务群组。 <BR>&nbsp;&nbsp;&nbsp;&nbsp; (预设值 = all groups) <BR>语法范例 <BR>sc query -列举所有执行中的服务与驱动程序状态。 <BR>sc query messenger&nbsp;&nbsp;-显示Messenger服务的状态。 <BR>sc queryex messenger -显示Messenger服务的延伸状态。 <BR>sc query type= driver -只列举执行中之驱动程序。 <BR>sc query type= service -只列举Win32服务。 <BR>sc query state= all -列举所有的服务与驱动程序。 <BR>sc query bufsize= 50 -列举一个50 byte大小的缓冲器。 <BR>sc query ri= 14&nbsp;&nbsp; -列举恢复索引号码为14之内容。 <BR>sc queryex group= "" -列举不在群组中之现行服务。 <BR>sc query type= service type= interact -列举所有具人、机通信功能之服务。 <BR>sc query type= driver group= NDIS -列举所有NDIS驱动程序。</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>由于这个工具对所有的服务控制选项提供了相当丰富的命令列介面且能简单地使用在一个指令码文件中,所以当我们在开发或侦错一个服务时,可以得到极大的帮助。</FONT></P></A><A 
            style="LINE-HEIGHT: 25px" name=203003>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7 
            size=5><B style="LINE-HEIGHT: 25px">Windows服务应用程序架构<BR 
            style="LINE-HEIGHT: 25px"> </B></FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>本节会解释那些将伺服应用程序转换成服务的附加基础,从而允许您们的应用程序可以被远端地控管。要了解Microsoft的服务架构有一些困难,这是由于每一个服务程序总是包含着至少二个线程,而那些线程在彼此间必须互相沟通所致。所以您必须要应付线程同步与线程间通讯的议题。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>一个单一执行档可以包含多个服务的情形是另一个您需要去考虑的议题。假如您回头看&nbsp;</FONT></A><FONT 
            style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2><A 
            style="LINE-HEIGHT: 25px" 
            href="http://www.acejoy.com/doc/serverside/3.htm#103_1" 
            target=_new>表3-1</A>&nbsp;的内容,您会发现有许多的服务皆被包含在Service.exe内。大部份的这些服务(如DHCP 
            Client、Messenger以及Alerter)在实作上都相当地简单。如果每一个服务皆要像一个分开的处理程序般执行,则会非常无效率,而且会花费一些位址空间与附加处理程序的成本。因为这个缘故,Microsoft允许一个单一执行档可以包含多个服务。Service.exe文件实际上包含20个不同的服务,包括刚才所述那叁个。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>要设计一个可执行的服务时,您必须自己考虑以下的叁个函数:</FONT></P><FONT 
            style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2>
            <UL style="LINE-HEIGHT: 25px">
              <LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
              face=arial color=#3e80d7 size=2><B 
              style="LINE-HEIGHT: 25px">&nbsp;处理程序之函数进入点&nbsp;</B></FONT>这个函数即是您现在应该要非常熟悉的标准(w)main或是(w)WinMain函数。对一个服务来说,这个函数为一个整体初始化处理程序然后它会呼叫一个与本机系统之SCM连接的特别函数。由此点看来,SCM会取得您的主要线程之控制权。只有在可执行的所有服务停止执行时,您的程序代码才会取回控制权。<BR 
              style="LINE-HEIGHT: 25px">  
              <LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
              face=arial color=#3e80d7 size=2><B 
              style="LINE-HEIGHT: 25px">&nbsp;服务的ServiceMain函数&nbsp;</B></FONT>您必须为每个包含在您的可执行档中的服务实作ServiceMain函数。执行一个服务时,SCM会产生一个在您处理程序中的线程,以执行您的ServiceMain函数。当该线程从ServiceMain函数中回传时,SCM会考虑停止服务。注意这个函数不一定要称为ServiceMain;您可以为它取一个任何您想要的名称。<BR 
              style="LINE-HEIGHT: 25px">  
              <LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
              face=arial color=#3e80d7 size=2><B 
              style="LINE-HEIGHT: 25px">&nbsp;服务的HandlerEx函数&nbsp;</B></FONT>每一个服务必须拥有一个与它关联的HandlerEx函数。SCM会呼叫服务的HandlerEx函数以与服务沟通。在HandlerEx函数中的程序代码会被您的主要处理程序线程执行。HandlerEx函数不是执行必要的动作就是必须传达SCM指令给线程以透过使用一些线程内部通讯的形式来执行服务的ServiceMain函数。注意每一个服务可以拥有属于它自己的HanderEx函数,或者多个服务可以共享一个HanderEx函数。传递给HanderEx函数的其中一个参数指出SCM希望与哪一些服务沟通。这个函数可以不叫做HanderEx,您可以为它取一个您想要的名称。<BR 
              style="LINE-HEIGHT: 25px">  </LI></UL></FONT>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>图3-7可以帮助您正确地了解这个架构。它说明了一个可执行之服务内存在的二个服务以及处理程序间通讯(ITC)与线程间通讯(IPC)。在未来的章节中,会仔细的检视这叁个函数以及说明它们的责任为何。建议您在阅读时可以参考此图。</FONT></P>
            <P><BR style="LINE-HEIGHT: 25px"> </P>
            <CENTER style="LINE-HEIGHT: 25px">
            <P><INPUT id=7 style="LINE-HEIGHT: 25px" type=image height=653 
            width=496 src="3.1.2 服务应用程序.files/3-7.gif" border=0 
            &#111nclick="imgclick"></P></CENTER>
            <CENTER style="LINE-HEIGHT: 25px">
            <TABLE style="LINE-HEIGHT: 25px" border=0>
              <TBODY style="LINE-HEIGHT: 25px">
              <TR style="LINE-HEIGHT: 25px">
                <TD style="LINE-HEIGHT: 25px" align=middle><FONT 
                  style="LINE-HEIGHT: 25px" face=arial color=#000000 
                  size=2><FONT style="LINE-HEIGHT: 25px" face=arial 
                  color=#3e80d7 size=2><B 
                  style="LINE-HEIGHT: 25px">&nbsp;图3-7&nbsp;</B></FONT>Windows服务应用程序架构</FONT></TD></TR></TBODY></TABLE></CENTER>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7 
            size=4><B style="LINE-HEIGHT: 25px">处理程序之进入点函数:(w)main或(w)WinMain<BR 
            style="LINE-HEIGHT: 25px"> </B></FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>当管理者想要启动一个服务时,不管该执行文件所包含的服务是否已执行,都由SCM来决定。如果它没有被执行,则SCM会将该执行档产生出来。此处理程序之主要线程的主要任务是执行整个程序的初始化(应该在服务之ServiceMain函数中完成初始化的动作)。</FONT></P>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>在初始化完成后,该进入点函数必须与SCM联系,以决定现在应该接管哪一个程序的控制。为了要与SCM接触,首先进入点函数必须配置和初始化一个SERVICE_TABLE_ENTRY结构的阵列:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">typedef struct _SERVICE_TABLE_ENTRY { <BR> PTSTR lpServiceName; // 服务的内部名称 <BR>LPSERVICE_MAIN_FUNCTION lpServiceProc; // 服务的ServiceMain <BR>} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>第一个成员表示内部、服务的计划性名称,第二个成员则是服务之ServiceMain回呼函数的位址。如果该执行档内只包含了一个服务,则SERVICE_TABLE_ENTRY结构的阵列必须利用以下的方式初始化:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">SERVICE_TABLE_ENTRY ServiceTable[] = { <BR> { TEXT("ServiceName1"), ServiceMain1 }, <BR> { NULL, NULL}&nbsp;&nbsp; // Marks end of array };</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>假如您的执行档内包含了叁个服务,您必须使用以下的方法来初始化它,就像这样:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">SERVICE_TABLE_ENTRY ServiceTable[] = { <BR> { TEXT("ServiceName1"), ServiceMain1 }, <BR> { TEXT("ServiceName2"), ServiceMain2 }, <BR> { TEXT("ServiceName3"), ServiceMain3 }, <BR> { NULL, NULL }&nbsp;&nbsp; // Marks end of array };</PRE></FONT></DIV>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>存在阵列中的最后一个结构必须将二个成员皆设定为NULL,以表示它为该阵列的结尾。现在该处理程序经由呼叫StartServiceCtrlDispatcher来与SCM连接:</FONT></P>
            <DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT 
            style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">BOOL StartServiceCtrlDispatcher( <BR> CONST SERVICE_TABLE_ENTRY* pServiceTable);</PRE></FONT></DIV>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?