专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »C 教程 » vc编写windows服务:Windows服务编写原理及探讨(3) »正文

vc编写windows服务:Windows服务编写原理及探讨(3)

来源: 发布时间:星期四, 2009年2月12日 浏览:93次 评论:0


( 3)对服务深入讨论的下

  现在我们还剩下可以在细节上讨论那就是服务CtrlHandler

  当RegisterServiceCtrlHandlerSCM得到并保存这个回调地址个SCP调个告诉SCM如何去控制服务Win32现在已经有10个预定义控制请求:

Control code
Meaning

SERVICE_CONTROL_STOP Requests the service to stop. The hService handle must have SERVICE_STOP access.
SERVICE_CONTROL_PAUSE Requests the service to pause. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_CONTINUE Requests the paused service to resume. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_INTERROGATE Requests the service to update immediately its current status information to the service control manager. The hService handle must have SERVICE_INTERROGATE access.
SERVICE_CONTROL_SHUTDOWN Requests the service to perform cleanup tasks, because the system is shutting down. For more information, see Remarks.
SERVICE_CONTROL_PARAMCHANGE Windows 2000: Requests the service to reread its startup parameters. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_NETBINDCHANGE Windows 2000: Requests the service to update its network binding. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_NETBINDREMOVE Windows 2000: Noties a network service that a component for binding has been removed. The service should reread its binding information and unbind from the removed component.
SERVICE_CONTROL_NETBINDENABLE Windows 2000: Noties a network service that a disabled binding has been enabled. The service should reread its binding information and add the binding.
SERVICE_CONTROL_NETBINDDISABLE Windows 2000: Noties a network service that _disibledevent=>Windows 2000字样就是2000中新添加控制代码除了这些代码的外服务也可以接受用户定义范围在128-255的间代码

  当CtrlHandler收到个SERVICE_CONTROL_STOP

、SERVICE_CONTROL_PAUSE、 SERVICE_CONTROL_CONTINUE控制代码时候SetServiceStatus必须被去确认这个代码并指定你认为服务处理这个状态变化所需要时间

  例如:你服务收到了停止请求首先要把SERVICE_STATUS结构dwCurrentState成员设置成SERVICE_STOP_PENDING这样可以使SCM确定你已经收到了控制代码个服务暂停或停止操作正在执行时候必须指定你认为这种操作所需要时间:这是个服务也许不能立即改变它状态它可能必须等待个网络请求被完成或者数据被刷新到个驱动器上指定时间思路方法就像我上章说那样用成员dwCheckPo和dwWaitH来指明它完成状态改变所需要时间如果需要可以用增加dwCheckPo成员值和设置dwWaitH成员值去指明你期待服务到达下时间方式周期性报告进展情况

  当整个启动过程完成的后要再SetServiceStatus这时就要把SERVICE_STATUS结构dwCurrentState成员设置成SERVICE_STOPPED当报告状态代码同时定要把成员dwCheckPo和dwWaitH设置为0服务已经完成了它状态变化暂停或继续服务时候思路方法也

  当CtrlHandler收到个SERVICE_CONTROL_INTERROGATE控制代码时候服务将简单将dwCurrentState成员设置成服务当前状态同时把成员dwCheckPo和dwWaitH设置为0然后再SetServiceStatus就可以了

  在操作系统关闭时候CtrlHandler收到个SERVICE_CONTROL_SHUTDOWN控制代码服务根本无须回应这个代码系统即将关闭它将执行保存数据所需要最小行动集这是为了确定机器能及时关闭缺省时系统只给很少时间去关闭所有服务MSDN里面说大概是20秒时间不过那可能是Windows NT 4设置在我Windows 2000 Server里这个时间是10秒你可以手动修改这个数值它被记录在HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control子键里面WaitToKillServiceTimeout单位是毫秒

\" width=493>

  当CtrlHandler收到任何用户定义代码时它应该执行期望用户自定义行动除非用户自定义行动要强制服务去暂停、继续或停止否则不调SetServiceStatus如果用户定义行动强迫服务状态发生变化SetServiceStatus将被去设置dwCurrentState、dwCheckPo和dwWaitH具体控制代码和前面说

  如果你CtrlHandler需要很长时间执行操作千万要注意:假如CtrlHandler在30秒内没有返回SCM将返回这不是我们所期望所以如果出现上述情况最好办法是再建立个线程让它去继续执行操作以便使得CtrlHandler能够迅速返回例如当收到个SERVICE_CONTROL_STOP

请求时候就像上面说服务可能正在等待个网络请求被完成或者数据被刷新到个驱动器上而这些操作所需要时间是你不能估计那么就要建立个新线程等待操作完成后执行停止命令CtrlHandler在返回的前仍然要报告SERVICE_STOP_PENDING状态当新线程执行完操作的后再由它将服务状态设置成SERVICE_STOPPED如果当前操作时间可以估计到就不要这样做仍然使用前面交待思路方法处理

  CtrlHandler我就先讲这些下面说说服务如何安装个服务可以使用CreateService将服务信息添加到SCM数据库

SC_HANDLE CreateService( SC_HANDLE hSCManager, // handle to SCM database LPCTSTR lpServiceName, // name of service to start LPCTSTR lpDisplayName, // display name DWORD dwDesiredAccess, // type of access to service DWORD dwServiceType, // type of service DWORD dwStartType, // when to start service DWORD dwErrorControl, // severity of service failure LPCTSTR lpBinaryPathName, // name of binary file LPCTSTR lpLoadOrderGroup, // name of load ordering group LPDWORD lpdwTagId, // tag identier LPCTSTR lpDependencies, // .gif' /> of dependency names LPCTSTR lpServiceStartName, // account name LPCTSTR lpPassword // account password );

  hSCManager是个标示SCM数据库句柄可以简单通过OpenSCManager得到

SC_HANDLE OpenSCManager( LPCTSTR lpMachineName, // computer name LPCTSTR lpDatabaseName, // SCM database name DWORD dwDesiredAccess // access type );

  lpMachineName是目标机器名字还记得我在第章里说过可以在其它机器上面安装服务吗?这就是实现思路方法对方机器名字必须以“\\\\”开始如果传递NULL或者个空话就默认是本机

  lpDatabaseName是目标机器上面SCM数据库名字但MSDN里面说这个参数要默认设置成SERVICES_ACTIVE_DATABASE如果传递NULL就默认打开SERVICES_ACTIVE_DATABASE所以我还没有真搞明白这个参数存在意义总的使用时候传递NULL就行了

  dwDesiredAccess是SCM数据库访问权限具体值见下表:

Object access
Description

SC_MANAGER_ALL_ACCESS Includes STANDARD_RIGHTS_REQUIRED, in addition to all of the access types listed in this table.
SC_MANAGER_CONNECT Enables connecting to the service control manager.
SC_MANAGER_CREATE_SERVICE Enables calling of the CreateService function to create a service object and add it to the database.
SC_MANAGER_ENUMERATE_SERVICE Enables calling of the EnumServicesStatus function to list the services that are in the database.
SC_MANAGER_LOCK Enables calling of the LockServiceDatabase function to acquire a lock _disibledevent=>


SC_MANAGER_QUERY_LOCK_STATUS Enables calling of the QueryServiceLockStatus function to retrieve the lock status information for the database.

  想要获得访问权限似乎没那么复杂MSDN里面说所有进程都被允许获得对所有SCM数据库SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS权限这些权限使得你可以连接SCM数据库枚举目标机器上安装服务和查询目标数据库是否已被锁住但如果要创建服务首先你需要拥有目标机器管理员权限传递SC_MANAGER_ALL_ACCESS就可以了这个返回句柄可以被CloseServiceHandle关闭

  lpServiceName是服务名字lpDisplayName是服务在“服务”管理工具里显示名字

  dwDesiredAccess也是访问权限个比上面还长个表各位自己查MSDN吧我们要安装服务仍然简单传递SC_MANAGER_ALL_ACCESS

  dwServiceType是指你服务是否和其它进程相关联般是SERVICE_WIN32_OWN_PROCESS表示不和任何进程相关联如果你确认你服务需要和某些进程相关联就设置成SERVICE_WIN32_SHARE_PROCESS当你服务要和桌面相关联时候需要设置成SERVICE_INTERACTIVE_PROCESS

  dwStartType是服务启动方式服务有 3种启动方式分别是“自动(SERVICE_AUTO_START)”“手动(SERVICE_DEMAND_START)”和“禁用(SERVICE_DISABLED)”在MSDN里还有另外两种方式不过是专为驱动设置

  dwErrorControl决定服务如果在系统启动时候启动失败话要如何办


意义

SERVICE_ERROR_IGNORE 启动记录发生但继续启动
SERVICE_ERROR_NORMAL 启动记录发生并弹出个消息框但仍继续启动
SERVICE_ERROR_SEVERE 启动记录发生如果是以last-known-good configuration启动启动会继续否则会以last-known-good configuration重新启动计算机
SERVICE_ERROR_CRITICAL 启动记录发生如果可能如果是以last-known-good configuration启动启动会失败否则会以last-known-good configuration重新启动计算机好严重

  lpBinaryPathName是服务路径MSDN里面特别提到如果服务路径里面有空格定要将路径用引号引起来例如\"d:\\\\my share\\\\myservice.exe\"就定要指定为\"\\\"d:\\\\my share\\\\myservice.exe\\\"\"

  lpLoadOrderGroup意义在于如果有组服务要按照顺序启动这个参数用于指定个组名用于标志这个启动顺序组不过我还没有用过这个参数服务如果不属于任何启动顺序组只要传递

NULL或者个空串就行了

  lpdwTagId是应用了上面参数的后要指定专用于驱动和本文内容无关传递NULL

  lpDependencies标示用于指明串服务名字或者个启动顺序组当和个启动顺序组建立关联时候这个参数含义就是只有你指定启动顺序组里有至少个经过对整个组里所有成员已经全部尝试过启动后有至少个成员成功启动服务才能启动不需要建立依存关系仍是传递NULL或者个空但如果你要指定启动顺序组必须为组名加上SC_GROUP_IDENTIFIER前缀组名和服务名是共享个命名空间

  lpServiceStartName是服务启动账号如果你设置你服务关联类型是SERVICE_WIN32_OWN_PROCESS你需要以DoName\\UserName格式指定用户名如果这个账户在你本机用.\\UserName就可以指定如果传递NULL会以本地系统账户登陆如果是Win NT 4.0或更早版本如果你指定了SERVICE_WIN32_SHARE_PROCESS就必须传递.\\指定服务使用本地系统账户最后如果你指定了SERVICE_INTERACTIVE_PROCESS你必须使服务运行在本机系统账户

  看名字就知道了lpPassword是账户密码如果指定系统账户传递NULL如果账户没有密码传递空

  总的服务基本原理就是这样子了到了这里这篇文章似乎可以告段落了但实际上还有很多内容必须要讨论所以我还不能草草收笔敬请关注下

0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: