4.1 服务控制程序.htm
来自「Windows2000后台服务程序开发手册」· HTM 代码 · 共 628 行 · 第 1/5 页
HTM
628 行
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">Base(系统哔哔声)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">指标通讯埠(支援滑鼠)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">键盘通讯埠(支援键盘)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">指标类别(支援多个滑鼠)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">键盘类别(支援多个键盘)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">Video Init(支援影像)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">影像(支援影像晶片)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">影像储存(支援多个影像)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">文件系统(支援CD-ROM与NTFS文件系统)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">事件记录(支援事件记录)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">资料流驱动程序<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">NDIS包装函数<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">PNP_TDI(支援NetBT与TCP/IP)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">NDIS(支援网路)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">TDI(支援AFD网路与DHCP)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">NetBIOSGroup(支援NetBIOS)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">PlugPlay<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">SpoolerGroup(支援列印集区)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">NetDDEGroup(支援网路DDE)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">并列仲裁器(支援并列埠)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">Extended base(支援数据机、序列与并列)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">远端验证RemoteValidation(支援net logon)<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">PCI设定<BR style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">MS处理<BR style="LINE-HEIGHT: 25px">
</LI></UL></FONT>
<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">HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ServiceGroupOrder</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>就像系统开机一样,它会反覆地执行这个清单、载入任何的设备驱动程序以及属于每一个部份的服务。例如,在载入属于SCSI
miniport群组之设备驱动程序与服务前即载入包含在系统保留群组中的所有设备驱动程序与服务。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>当您加入一个服务至SCM资料库中时,可以经由在CreateService的pszLoadOrderGroup参数中传递群组的名称,指定它为上述之已定义群组清单中的一项。通常,您的服务不需要在系统开机周期即载入,而是应该在所有群组设备与服务开始启动并执行后才载入执行。为了确定您的服务在所有的系统之关键设备驱动程序与服务之后才载入执行,您只需简单地在pszLoadOrderGroup参数中传递NULL即可。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>如果您增加了一个设备驱动程序至SCM中(相对于一个服务),则可以在经由指定一个标签ID,在建立驱动程序的启动时间取得更多的资料点(Granularity)。服务无法利用这个额外的资料点,并且必须总是传递NULL给CreateService的pdwTagId参数。若您对设备驱动程序有与趣,可参阅在Platform
SDK文件与DDK文件中讨论pdwTagId参数以及二个附加的选项(SERVICE_BOOT_
START与SERVICE_SYSTEM_START)。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>除了告诉SCM您的服务属于一个特定载入顺序的群组外,您还可以告诉SCM您的服务要求某些其他的服务与群组需要在您的服务可以执行前即已执行。例如,Computer
Browser服务要求Workstation与Server服务必须在它可以正确地执行前即已执行,而ClipBook服务则要求Network
DDE服务被执行。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>指定您的服务依存于哪些服务,比表明您服务为某个群组的一部份更为有用。您会使用CreateService的pszDependencies参数来告知SCM资料库您的服务依存于哪一些服务。如果您的服务没有存在依存关系,则只需传递NULL给此参数即可。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>因为您必须传递一个透过零分离的名称之双倍终止位址阵列,所以pszDependencies是一个非常奇特的参数。以另一种方式来说,pszDependencies参数必须指向一个包含终止字串与一个缓冲器尾端之额外空字元的内存区块。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>所以为了建立一个依存于Workstation服务的服务(像Alerter服务即是),在传递它给CreateService前,您应先设定pszDependencies(程序代码如下所示):</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">// 在下面的缓冲器中以二个空字元结束 <BR>PCTSTR pszDependencies = TEXT("LanmanWorkstation\0"); <BR>CreateService(..., pszDependencies, ...);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>而建立一个依存于Workstation服务与Remote Procedure
Call(RPC)服务(如Messenger服务)的服务时,您将以如下的方式设定pszDependencies:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">// 在下面的缓冲器中分开一个空字元的字串并以二个空字元结束 <BR>PCTSTR pszDependencies = TEXT("LanmanWorkstation\0RpcSs\0"); <BR>CreateService(..., pszDependencies, ...);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>一个服务也能被一个群组而非一个单一的服务依存,但是这是非常不寻常的情形。载入次序群组上的从属意味着在一个尝试启动群组中所有成员的动作被完成后,该群组中至少有一个成员为执行状态。为了在一个pszDependencies缓冲器中指定一个群组,您必须在群组名称前加上一个特定的SC_GROUP_IDENTIFIER字元,它被定义在WinSvc.h中,如下所示:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">#define SC_GROUP_IDENTIFIERW L’+’ <BR>#define SC_GROUP_IDENTIFIERA ’+’ <BR>#ifdef UNICODE <BR>#define SC_GROUP_IDENTIFIER SC_GROUP_IDENTIFIERW <BR>#else <BR>#define SC_GROUP_IDENTIFIER SC_GROUP_IDENTIFIERA <BR>#endif</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>因此,为了要建立一个依存于Workstation服务与TDI群组的服务,您应如以下的方式来设定pszDependencies:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">// 在下面的缓冲器中指定二个依存关系:Workstation服务与TDI群组(一个「+」在TDI之前的群组) <BR>PCTSTR pszDependencies = TEXT("LanmanWorkstation\0+TDI\0"); <BR>CreateService(..., pszDependencies, ...);</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>当设定pszDependencies值时,您可以依自己的方式指定许多服务与群组。只要记得在每一个服务或群组间放置一个空字元与在所有群组名称前放入一个加号,以及在结尾引用前加入一个终止之空字元。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>我们现在可以开始说明CreateService之最终二个参数:pszUserName与pszUserPswd。这二个参数允许您在使用者帐户下指定哪一些服务可被执行。为了使服务在本机帐户下执行(大部份的情形),只需传递NULL给此二个参数即可。如果您想让服务在一个特定的使用者帐户下执行,则以DomainName\UserName形式来传送一个帐户名称给pszUserName参数,并传递使用者帐户的密码至pszUserPswd参数中。</FONT></P>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3
Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>互动式的服务必须被设定在一个本机帐户下执行。若您试图在非本机帐户下加入一个互动式的服务,则CreateService无法增加服务至SCM资料库中。</FONT></P>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>如果CreateService成功的将一个服务加入至SCM资料库中,此时会回传一个非NULL的handle。由另一个函数来要求这个handle,以操作服务。当您要结束使用它时,请确定您已将这个handle传递给CloseServiceHandle函数。如果CreateService执行失败,它会回传一个NULL值,并且一个呼叫至GetLastError的函数会回传一个值,以指示执行失败的原因。以下为CreateService可能执行失败的大部份原因:</FONT></P><FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2>
<UL style="LINE-HEIGHT: 25px">
<LI
style="LINE-HEIGHT: 25px">从OpenSCManager回传的handle中,没有SC_MANAGER_CREATE_SERVICE的存取。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">新的服务指定了一个循环的依存关系。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">服务的显示名称已经存在。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">被指定的服务名称是无效的。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">一个参数为无效的。<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px">被指定的使用者帐户不存在。<BR
style="LINE-HEIGHT: 25px"> </LI></UL></FONT>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>我经常将服务编写成可执行的服务程序,所以它们能够自行安装。在我的(w)main或(w)WinMain函数中,若以命令列传递一个「-install」参数,则我会呼叫一个ServiceInstall函数(显示在以下的程序片段中)。在上一章中展示的TimeService范例服务程序即说明了这个技术。</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">void ServiceInstall(PCTSTR pszInternalName, PCTSTR pszDisplayName, <BR> DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl) { <BR> // 开启SCM资料库以增加一个服务 <BR> SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); <BR> // 取得我们的服务之可执行完整路径 <BR> char szModulePathname [_MAX_PATH]; <BR> GetModuleFileName(NULL, szModulePathname, sizeof(szModulePathname)); <BR> // 增加此服务至SCM资料库 <BR> SC_HANDLE hService = CreateService( <BR> hSCM, pszInternalName, pszDisplayName, 0, dwServiceType, <BR> dwStartType, dwErrorControl, szModulePathname, <BR> NULL, NULL, NULL, NULL, NULL); <BR> // 关闭新建立之服务与SCM <BR> CloseServiceHandle(hService); <BR> CloseServiceHandle(hSCM); <BR>}</PRE></FONT></DIV>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3
Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>为了要更清楚地说明,所以前面所示之程序代码并没有处理任何的错误检查。所以OpenSCManager与CreateService可能会因为许多原因而执行失败。当您在增加类似上述程序代码至您的应用程序中时,请适当的增加错误检查机制。</FONT></P>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?