3.2.1 服务应用程序.htm

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

HTM
499
字号
            size=2>就像位于HKEY_LOCAL_MACHINE中的设定一般,虽然一个服务并不需要存取它,但是存在HKEY_USERS\.DEFAULT中的设定值还是可以被服务与应用程序使用。一个存放于HKEY_USERS下之特定的使用者设定不能被使用,除非该使用者登入至系统中。由于服务通常会在本机帐户下执行,所以服务不该试图去存取任何储存在HKEY_USERS中特定使用者帐户内容。相同的一个本机帐户服务也不该使用HKEY_CURRENT_USER来存取登录之内容。关于登录设定与使用者设定档的更多资讯,请参阅&nbsp;</FONT></A><FONT 
            style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2><A 
            style="LINE-HEIGHT: 25px" 
            href="http://e-msbooks.com/relaunch/XML/paser.asp?src=957-2085-84-0_205.xml#" 
            target=_new>第五章</A>&nbsp;。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7 
            size=4><B style="LINE-HEIGHT: 25px">核心物件之安全性<BR 
            style="LINE-HEIGHT: 25px"> </B></FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>本节会介绍许多开发者皆会遇到的一个常见问题。即当他们的客户端应用程序与服务在同一台机器上执行而且客户端与服务尝试分享一个核心物件时所发生的问题。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>以下为解决方案。您的服务开始执行并且呼叫CreateFileMapping去建立一个文件对应的物件。CreateFileMapping建立了一个核心物件,所以它的参数之一是一个SECURITY_ATTRIBUTES资料结构的位址。假如您像多数的程序开发者一样的话,则您会传递NULL给此参数,因为核心物件会被以「预设的安全性」建立。请注意我所提的是「预设的安全性」,而不是「没有安全性」。预设的安全性表示在物件被建立时经由安全性条件而定义之物件存取控制。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>例如,一个核心物件会被本机服务所建立,在预设的情形下,它被允许可以完全的存取任何不在执行中的本机帐户,并只允许可以读取与执行本端管理者之成员群组。所以如没有一个本机服务以预设的安全性建立了一个文件对应的物件,则一个在本机管理员帐户下执行的应用程序可以从读取文件对应物件,但不能以任何方式对它做写入的动作。在任何其他帐户下执行的应用程序不能完全存取文件对应物件。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>现在,我只是想要使您知道这个议题。有很多关于客户端与服务之核心物件安全性的内容可以谈,而且有很多方法可以处理它,但是必须是在您更了解Windows安全性的前提下。所以建议您阅读本书第五篇中有关安全性的章节,以取得所有的细节。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7 
            size=4><B style="LINE-HEIGHT: 25px">互动式的服务、视窗配置与桌面<BR 
            style="LINE-HEIGHT: 25px"> </B></FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>本节只讨论有关服务如何影响视窗配置与桌面之内部操作的议题。有关视窗配置与桌面的更多资讯,请参阅&nbsp;<A 
            style="LINE-HEIGHT: 25px" 
            href="http://e-msbooks.com/relaunch/XML/paser.asp?src=957-2085-84-0_210.xml#" 
            target=_new>第十章</A>&nbsp;。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>当您建立了一个核心物件时,您可以指定它应该被安全地经由一个SECURITY_ATTRIBUTES结构传送。但是像视窗与功能表这种使用者物件要如何做呢?使用者物件使用了一个不同的型式;它们不会被开启或关闭—只要在您需要的时候存取它们即可,如此可使程序代码容易编写以及增进效能。另外,使用存在于16位元之Windows作业系统中的物件并不以任何形式来支援安全性。如果Microsoft加入SECURITY_ATTRIBUTES结构至CreateWindow以及CreateMenu中,开发者在放置他们的16位元程序代码时会产生困难。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>Microsoft需要一个在不影响已存在之函数以及不影响您使用物件的前提下,让使用者物件变得安全的方式。这包括了所有关于视窗配置与桌面的部份。一个视窗配置为一个<FONT 
            style="LINE-HEIGHT: 25px" face=arial color=#3e80d7 size=2><B 
            style="LINE-HEIGHT: 25px">&nbsp;逻辑&nbsp;</B></FONT>的键盘、滑鼠以及显示器之集合体。「逻辑」一字表示设备不一定真的存在。当系统被启动时,它会建立互动式的视窗配置,称为「WinSta0」;实体的键盘、滑鼠以及显示器会与这个视窗配置关联。一个视窗配置也可以包含它所拥有的记事本、一个通用元素的集合以及一个桌面物件群组。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>一个桌面由一个逻辑的显示外观以及一个使用者物件的集合所组成:视窗、功能表以及拦截程序(Hook)。线程也会与桌面联系(请参阅Platform 
            SDK文件中的SetThreadDesktop与GetThreadDesktop函数的内容)。假如一个已与桌面关联的线程试图传送一个讯息至被另一个桌面建立的视窗时,线程不能在属于另一个桌面之线程上安装拦截程序。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>就像视窗配置一样,桌面会被它的字串名称所确认。WinLogon.exe会建立叁个桌面:</FONT></P><FONT 
            style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2><BR>
            <UL style="LINE-HEIGHT: 25px"><BR>
              <LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
              face=arial color=#3e80d7 size=2><B 
              style="LINE-HEIGHT: 25px">&nbsp;WinLogon&nbsp;</B></FONT>事先配置登入对话方块。在使用者登入后,WinLogon.exe会转换至预设桌面。<BR 
              style="LINE-HEIGHT: 25px">  <BR>
              <LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
              face=arial color=#3e80d7 size=2><B 
              style="LINE-HEIGHT: 25px">&nbsp;Default&nbsp;</B></FONT>Explorer.exe与所有使用者的应用程序所显示之视窗的位置。每当一个应用程序执行时,它会在桌面执行。<BR 
              style="LINE-HEIGHT: 25px">  <BR>
              <LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
              face=arial color=#3e80d7 size=2><B 
              style="LINE-HEIGHT: 25px">&nbsp;Screen 
              saver&nbsp;</B></FONT>当使用者闲置了一段时间后,执行系统的萤幕保护程序。<BR 
              style="LINE-HEIGHT: 25px">  </LI></UL></FONT><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>系统自己拥有本身的特定使用者帐户。所以实际上有二个「使用者」曾经存取机器:即本机使用者及已登入的使用者。当然,如果这两个使用者正在单一机器上执行应用程序,您不用等待所有应用程序之视窗在单一的显示设备中显现,因为二个使用者皆会要求分配一个属于自己的视窗配置。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>由于这个原因,本机帐户会被给予一个属于它的视窗配置,称为「Service-0x0-3e7$」(那些数字是服务的登入SID),以及属于它的桌面,称为Default。视窗配置为非互动式而且没有一个实体的键盘、滑鼠与显示器—即本机「使用者」不是一个真实的人类,因此不需要去打字、按下滑鼠或「察看」任何东西。任何正在此视窗配置下之桌面上执行的应用程序皆可以建立一个视窗,但是该视窗不会被显示给已登录的使用者看。这就是为什么服务不应显示一个使用者介面的原因:没有人会看到它,而且线程会为了等待输入而被悬置,因此可能永远都无法被执行。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>使用服务嵌入式管理单元,您可以显示一个服务的内容。您可以回想一下登入身份页签内容包含了一个允许服务与桌面互动的核取方块。当它被选择时,这个选项会让SCM以互动式视窗配置之预设桌面的方式启动一个服务:「WinSta0\Default」。注意您只能在您的服务执行于本机帐户的情形下才能选择该选项。因为本机帐户拥有较高的存取权限并且它能够存取互动式的使用者视窗配置与桌面。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>有一个与服务跟桌面互动有关的问题即是预设值。桌面不会经常被显示。当萤幕保护程序执行或是使用者登出系统时,服务的使用者介面还保留在预设的桌面上,但是在下一个使用者登入前,该使用者介面不会被显示。另一个问题是它使系统相当的不安全。例如,一个标准的应用程序可以传送视窗讯息至服务的视窗中。该应用程序使用已登入使用者的安全条件执行,但是此应用程序现在正与一个经由一个不安全通道执行本机帐户之处理程序互相通讯。一个被限制的使用者可以轻易地存取不应被他们取得的系统资源。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>这里有一个范例:一个服务正以本机帐户执行而且它正显示在互动式预设桌面的视窗中。正常的情形下,当已登入的使用者试图使用工作管理员的处理程序页签去删除一个服务时,会出现一个拒绝存取或类似的讯息而且该服务会继续执行。这个功能当然是被需要的。您不会想要让一个以Guest帐户登入至系统上的使用者删除一个服务器的服务、妨碍位于网路上的其他使用者存取目录、文件与打印机(特别是当服务器服务在Service.exe中执行时)。然而,假如本机服务建立了一个互动式的视窗,则已登入的使用者会在工作管理员的应用程序页签中看见它。此时选择工作结束会传送一个WM_CLOSE讯息至视窗中,使得一个服务能被删除。</FONT></P><BR>
            <HR style="LINE-HEIGHT: 25px">
            <BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3 
            Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>由于上述的所有理由,Microsoft强烈地建议使用允许服务与桌面互动核取方块。事实上,一个管理员可以经由与桌面互动的方式将以下所示之登录子机码NoInteractiveServices值设定为非0值以禁止服务执行:</FONT></P><BR>
            <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\Windows</PRE></FONT></DIV><BR>
            <HR style="LINE-HEIGHT: 25px">
            <BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>所以在一个特定的使用者帐户下执行服务如何?当SCM在一个特定的使用者帐户下执行一个可执行的服务时,SCM会先对使用者做验证,请使用者提供使用者名称与密码会成为服务设定资讯的一部份(使用者名称被储存在登录中,而密码则储存在一个安全的LSA文件中)。这个验证过程建立了一个登入工作阶段,表示哪一个取得自己拥有之非互动式视窗与桌面。可执行服务现在已包含了使用这个专用的视窗配置与桌面,其名称大概是「UserAccountLogonSID\ 
            Default」,「UserAccountLogonSID」是一个在验证期间产生的唯一数字。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>这个唯一的鉴定表示如果您拥有二个或多个设定在同一个使用者帐户下执行的服务,则每一个皆会取得它自己所拥有的登入SID、视窗配置以及桌面(如果它们在不同的处理程序中)—位于这些可执行服务中的线程不能经由使用者物件而互相通讯。这个唯一的鉴定也表示如果一个正在目前已使用互动式登入的使用者帐户下执行服务,则该服务的使用者介面不会被显示出来。反之,本机帐户只会被验证一次,所以所有分享同一个视窗配置与桌面以及可以经由使用者物件通讯的许多可执行服务会在本机帐户下执行。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>Microsoft已经加入一些特定的服务特性至常见的MessageBox(Ex)函数中。第一,当您传递了MB_SERVICE_NOTIFICATION标记时,不管哪一个桌面为WinLogon、预设或是正在执行萤幕保护程序,该函数皆会在互动式视窗配置之活动中桌面上显示讯息方块。这保证讯息方块会显示在显示设备中。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>第二,MessageBox(Ex)支援MB_DEFAULT_DESKTOP_ONLY标记。除了它只在互动式视窗配置的预设桌面上显示讯息方块外,此标记与MB_SERVICE_ 
            NOTIFICATION是很类似的:一个使用者必须登入才能看见该讯息方块。注意除非一个使用者已经看见讯息方块并且已按下按钮使其离开,否则MessageBox(Ex)不会返回。顺便一提,若要使一个服务不需在本机帐户下执行,也没有核取允许服务与桌面互动之核取方块时,不是使用MB_DEFAULT_DESKTOP_ONLY就是使用MB_SERVICE_NOTIFICATION标记来达到这个目的。系统会保证该讯息方块会被显示。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>如果您一直谨慎地跟随着我们的进度,则您应该会注意到在我使用为了创造互动式服务时所建立的每个方法时,使您的意志受挫了。如果您想制作一个提供使用者介面的服务时,应该如何做呢?这个回答很简单:建立一个分开的、使用一些IPC机制(RPC、COM、命名管道、套接字、内存映对文件等)与服务对谈的客户端应用程序。我知道有许多人不想这么做,因为他们必须建立一个可以自我执行的全新专案,但是建立一个分开的应用程序是正确且可得到最多支援的方法。如果您这么做的话,那么Microsoft便无法简单地打破您的架构。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>客户端应用程序应该在Windows 2000、Windows 
            98、UNIX或任何其他作业系统上执行。您可以建立一个以HTML为基础的使用者介面以与使用ActiveX控制或Active Server 
            Pages的服务沟通。您也应该为了MMC而考虑建立您的使用者介面之嵌入式管理单元。想想这个客户端应用程序为了您而开启的可能性,不是因为所有使用者介面被发布而限制它们。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>在移至这个主题之前,我想要多讨论一些有关使用者介面的议题:一些Windows函数会产生硬体错误的讯息方块。例如,如果您正从光碟执行一个应用程序并且移除了光碟片,此时系统会自动地显示一个讯息方块。如果系统没有显示讯息方块,它的另一个选择即是删除该处理程序。</FONT></P><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>它有被系统修改的可能性,所以硬体错误会被记录至事件记录中并且不会产生讯息方块。要改变系统的行为,您必须在以下所列之登录子机码中修改ErrorMode的值:</FONT></P><BR>
            <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\Windows</PRE></FONT></DIV><BR>
            <P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000 
            size=2>表3-4列出了ErrorMode的可能值。</FONT></P><BR>
            <CENTER style="LINE-HEIGHT: 25px"><BR>&nbsp; 
            <TABLE style="LINE-HEIGHT: 25px" border=0><BR>
              <TBODY style="LINE-HEIGHT: 25px"><BR>&nbsp;&nbsp;&nbsp; 
              <TR style="LINE-HEIGHT: 25px"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

                <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>定义是否显示硬体错误之讯息方块的ErrorMode值</FONT></TD><BR>&nbsp;&nbsp;&nbsp; 
              </TR><BR>&nbsp; </TBODY></TABLE><BR></CENTER><BR>
            <CENTER style="LINE-HEIGHT: 25px"><BR>&nbsp; 
            <TABLE style="LINE-HEIGHT: 25px" border=1><BR>
              <TBODY style="LINE-HEIGHT: 25px"><BR>&nbsp;&nbsp;&nbsp; 
              <TR style="LINE-HEIGHT: 25px"><BR>
                <TH style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
                  size=2>值</FONT> </TH><BR>
                <TH style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
                  size=2>说明</FONT></TH><BR>&nbsp;&nbsp;&nbsp; 
              </TR><BR>&nbsp;&nbsp;&nbsp; 
              <TR style="LINE-HEIGHT: 25px"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

                <TD style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
                  size=2>0(预设值)</FONT></TD><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
                <TD style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
                  size=2>系统会显示错误讯息方块。</FONT></TD><BR>&nbsp;&nbsp;&nbsp; 
              </TR><BR>&nbsp;&nbsp;&nbsp; 
              <TR style="LINE-HEIGHT: 25px"><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

                <TD style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px" 
                  size=2>1</FONT></TD><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

⌨️ 快捷键说明

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