📄 cb199910nt0602_f.asp.htm
字号:
<HTML>
<HEAD>
<TITLE>Writing NT Services</TITLE>
</HEAD>
<BODY>
<TABLE border=0 width="756" cellpadding=0 cellspacing=0>
<TR valign=top>
<TD width="10">
</TD>
<TD width="742">
<p class=ColumnTitle><font size="2">All
Systems Go</font></p>
<p class=ColumnSubtitle><font size="2">Windows
NT / NT Services / Windows Registry</font></p>
<p class=BodyText> </p>
<p class=Byline><font size="2">By Kent
Reisdorph</font></p>
<p class=BodyText> </p>
<p class=StoryTitle><font size="2"><b>Writing
NT Services</b></font></p>
<p class=StorySubtitle><font size="2"><b>Part
II:</b> Threads and Writing Interactive Services</font></p>
<p class=BodyText> </p>
<p class=BodyText> In Part
I, we began this series with a description of services and how they work under
NT. In this installment, we'll begin by discussing how to write a simple
service. We'll also try to understand the C++Builder-generated code for
services, and talk about service threads and installing and testing services. </p>
<p class=BodyText> </p>
<p class=Subheads>Writing a
Simple Service</p>
<p class=BodyText> The
example program for this section is called BeepSrvc. This service does nothing
more than beep the PC speaker once each second. A service that beeps every
second (or some other interval) is sort of the "Hello World" of NT services.
It's not exactly exciting, but it will show you how services work. The
service's name is BeepService. The header and source for the BeepService unit
is shown in Figures 1 and 2. </p>
<p class=BodyText> </p>
<p class=Code><span class=Code><span Class=CodeGrn>#ifndef
BeepSrvcUH</span></span></p>
<p class=Code><span class=Code><span Class=CodeGrn>#define
BeepSrvcUH</span></span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><span Class=CodeGrn>#include
<SysUtils.hpp> </span></span></p>
<p class=Code><span class=Code><span Class=CodeGrn>#include
<Classes.hpp> </span></span></p>
<p class=Code><span class=Code><span Class=CodeGrn>#include
<SvcMgr.hpp> </span></span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><b>class</b>
TBeepService : <b>public</b> TService</span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code><b>__published</b>: <i> <span Class=CodeBlue>// IDE-managed Components. </span></i></span></p>
<p class=Code><span class=Code> <b> void</b>
<b>__fastcall</b> Service1Execute(TService
*Sender); </span></p>
<p class=Code><span class=Code><b>private</b>: <i> <span Class=CodeBlue>// User declarations. </span></i></span></p>
<p class=Code><span class=Code><b>public</b>: <i> <span Class=CodeBlue>// User declarations. </span></i></span></p>
<p class=Code><span class=Code> <b> __fastcall</b>
TBeepService(TComponent* Owner); </span></p>
<p class=Code><span class=Code> PServiceController <b>__fastcall</b> GetServiceController(<b>void</b>);</span></p>
<p class=Code><span class=Code> <b> friend</b>
<b>void</b> <b>__stdcall</b> ServiceController(<b>unsigned</b>
CtrlCode); </span></p>
<p class=Code><span class=Code>};</span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><b>extern</b>
PACKAGE TBeepService *BeepService; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><span Class=CodeGrn>#endif</span></span></p>
<p class=Captions><b>Figure
1:</b> The header for
the BeepService unit. </p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><span Class=CodeGrn>#include
"BeepSrvcU.h" </span></span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><span Class=CodeGrn>#pragma
package(smart_init) </span></span></p>
<p class=Code><span class=Code><span Class=CodeGrn>#pragma
resource "*.dfm" </span></span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code>TBeepService
*BeepService; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><b>__fastcall</b>
TBeepService::TBeepService(TComponent* Owner) </span></p>
<p class=Code><span class=Code> : TService(Owner) </span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code>}</span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code>PServiceController
<b>__fastcall</b>
TBeepService::GetServiceController(<b>void</b>)</span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code> <b> return</b>
(PServiceController) ServiceController; </span></p>
<p class=Code><span class=Code>}</span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><b>void</b> <b
style='mso-bidi-font-weight:normal'>__stdcall</b> ServiceController(<b
style='mso-bidi-font-weight:normal'>unsigned</b> CtrlCode) </span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code> BeepService->Controller(CtrlCode); </span></p>
<p class=Code><span class=Code>}</span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><b>void</b> <b
style='mso-bidi-font-weight:normal'>__fastcall</b>
TBeepService::Service1Execute(TService *Sender) </span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code> <b> while</b>
(!Terminated) </span></p>
<p class=Code><span class=Code> { </span></p>
<p class=Code><span class=Code> MessageBeep(0); </span></p>
<p class=Code><span class=Code> Sleep(1000); </span></p>
<p class=Code><span class=Code> ServiceThread->ProcessRequests(<b
style='mso-bidi-font-weight:normal'>false</b>);</span></p>
<p class=Code><span class=Code> } </span></p>
<p class=Code><span class=Code>}</span></p>
<p class=Captions><b>Figure
2:</b> The source code
for the BeepService unit. </p>
<p class=BodyText> </p>
<p class=BodyText> As you
can see from these listings, this simple service contains very little code.
Most of the hard stuff is handled behind the scenes by the <i>TService</i> and <i>TServiceApplication</i>
classes. In fact, I wrote only four lines of code for this service. The rest of
the code was generated by C++Builder. I'll address the code generated by
C++Builder in the following section. </p>
<p class=BodyText> </p>
<p class=BodyText> This
service uses default values for all of the service's properties except for the <i
style='mso-bidi-font-style:normal'>Name</i> and <i>DisplayName</i> properties, both of which I have set to <i>BeepService</i>. </p>
<p class=BodyText> </p>
<p class=BodyText> This
service uses the default values for all other properties, allowing the service
to be stopped, paused, and continued from the SCP or by using one of the
service command-line utilities. The defaults also specify that this is a Win32
service, that it is not interactive (it cannot display a dialog box to the
user), and that it is set to auto-start when NT boots. </p>
<p class=BodyText> </p>
<p class=Subheads>Tip</p>
<p class=BodyText> You will
save yourself some headaches if you set the <i>Name</i>
and <i>DisplayName</i> properties to the
same value. In fact, you'll notice that when you set the <i>Name</i> property in the Object Inspector, the <i>DisplayName</i> property changes to match. It's easier to manage your
service during development when both the <i>DisplayName</i>
and <i>Name</i> have the same value. </p>
<p class=BodyText> </p>
<p class=BodyText> When I
first wrote this service, I set the <i>DisplayName</i>
property to <i>BeepService </i>and the <i>Name</i>
property to <i>BeepSrvc</i>. I then used the SC.EXE utility to start and stop
the service. I typed the following from the command line: </p>
<p class=BodyText> </p>
<p class=Code><span class=Code>sc stop
BeepService</span></p>
<p class=BodyText> </p>
<p class=BodyText> I kept
getting an error from SC.EXE when using this syntax. It took me a couple of
minutes to realize that I was passing the service's display name to SC.EXE when
I should have been passing the service's actual name. The display name is
simply the text that is displayed in the SCP for the service. The service name
is the text that the SCM uses to refer to the service. The proper command-line
syntax for stopping the service should have been the following: </p>
<p class=BodyText> </p>
<p class=Code><span class=Code>sc stop
BeepSrvc</span></p>
<p class=BodyText> </p>
<p class=BodyText> By
setting the <i>Name</i> and <i
style='mso-bidi-font-style:normal'>DisplayName</i> properties to the same
value, I eliminated the confusion caused by using two different values for
these properties. </p>
<p class=BodyText> </p>
<p class=Subheads>Understanding
the C++Builder-generated Code for Services</p>
<p class=BodyText> Before
we get into what little code this service contains, I want to spend a moment
discussing the code that C++Builder generates. You will find this code near the
top of the main source unit: </p>
<p class=BodyText> </p>
<p class=Code><span class=Code>PServiceController
<b>__fastcall</b>
TBeepService::GetServiceController(<b>void</b>)</span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code> <b> return</b>
(PServiceController) ServiceController; </span></p>
<p class=Code><span class=Code>}</span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><b>void</b> <b
style='mso-bidi-font-weight:normal'>__stdcall</b> ServiceController(<b
style='mso-bidi-font-weight:normal'>unsigned</b> CtrlCode) </span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code> BeepService->Controller(CtrlCode); </span></p>
<p class=Code><span class=Code>}</span></p>
<p class=BodyText> </p>
<p class=BodyText> Each
service must have a function that processes service control requests. This
function is commonly called the <i>service handler</i>. The service handler is
registered with Windows by the <i>TService</i>
class. As with many Windows callbacks, the service handler must be a standalone
function. (It can't be a class member function.) The code you see here is the
mechanism the VCL uses to implement the service handler. The implementation in
SvcMgr.pas looks like this: </p>
<p class=BodyText> </p>
<p class=Code><span class=Code>FStatusHandle
:= </span></p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -