⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cb199910nt0602_f.asp.htm

📁 C++builder学习资料C++builder
💻 HTM
📖 第 1 页 / 共 5 页
字号:
  

<p class=Code><span class=Code>&nbsp;&nbsp;RegisterServiceCtrlHandler(PChar(Name),  

GetServiceController); </span></p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> Granted,  

this is Object Pascal code, but it's easy enough to understand even if you  

aren't a Pascal programmer. This code calls the Windows <i>RegisterServiceCtrlHandler</i> function, passing the service name in  

the first parameter. The second parameter is a call to the service's <i  

style='mso-bidi-font-style:normal'>GetServiceController</i> method. As you can  

see from the earlier code snippet, this method returns a pointer to the  

standalone <i>ServiceController</i>  

function. Once registered, the <i>ServiceController</i>  

function will be called each time the service receives a control request from  

the SCM. It's not vital that you understand service control requests at this  

time, but I wanted to explain the meaning of these two functions. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> You may  

have noticed that the <i>ServiceController</i>  

function calls the service's <i>Controller</i>  

method. The <i>Controller</i> method is  

declared as protected in the <i>TService</i>  

class. How does the standalone <i>ServiceController</i>  

function gain access to the <i>Controller</i>  

method? If you look at the service's class declaration in Figure 1, you will  

notice that the <i>ServiceController</i>  

function is declared as a friend of the service class: </p>  

  

<p class=BodyText> &nbsp; </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=BodyText> &nbsp; </p>  

  

<p class=BodyText> This  

makes it possible for the <i>ServiceController</i>  

function to call the protected <i>Controller</i>  

method. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> Note:  

There is a minor bug in the code generation for service applications. When you  

create a new service, C++Builder gives the service a default name of Service1.  

It then generates a <i>ServiceController</i>  

function that looks like this: </p>  

  

<p class=BodyText> &nbsp; </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>&nbsp;&nbsp;Service1-&gt;Controller(CtrlCode); </span></p>  

  

<p class=Code><span class=Code>}</span></p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> Now  

let's say you change the service's <i>Name</i>  

property to <i>MyService</i>. C++Builder  

will change all of the references to Service1 with <i>MyService</i>, except the reference in the <i>ServiceController</i> function. Before your code will compile, you will  

have to manually change the code in the <i>ServiceController</i>  

function so that it uses the correct class name. In this case, you would have  

to modify the code as follows: </p>  

  

<p class=BodyText> &nbsp; </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>&nbsp;&nbsp;MyService-&gt;Controller(CtrlCode); </span></p>  

  

<p class=Code><span class=Code>}</span></p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Subheads>Service  

Threads and the <i>OnExecute</i> Event</p>  

  

<p class=BodyText> Each  

service has its own thread. The <i>ServiceThread</i>  

property is a pointer to the service's internal thread. <i>ServiceThread</i> is an instance of the <i>TServiceThread</i> class. <i>TServiceThread</i>  

is derived from <i>TThread</i>. <i  

style='mso-bidi-font-style:normal'>TServiceThread</i> only provides one method  

beyond the usual methods of <i>TThread</i>.  

That method is <i>ProcessRequests</i> and  

its purpose is to process service requests sent to the service by the SCM. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> For  

simple services, you can use the service's built-in thread. That's what the  

BeepService example does. All of the code for BeepService is in the service's <i  

style='mso-bidi-font-style:normal'>OnExecute</i> event handler: </p>  

  

<p class=BodyText> &nbsp; </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>&nbsp;&nbsp;<b> while</b>  

(!Terminated) </span></p>  

  

<p class=Code><span class=Code>&nbsp;&nbsp;{ </span></p>  

  

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;MessageBeep(0); </span></p>  

  

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;Sleep(1000); </span></p>  

  

<p class=Code><span class=Code>&nbsp;&nbsp;&nbsp;&nbsp;ServiceThread-&gt;ProcessRequests(<b  

style='mso-bidi-font-weight:normal'>false</b>);</span></p>  

  

<p class=Code><span class=Code>&nbsp;&nbsp;} </span></p>  

  

<p class=Code><span class=Code>}</span></p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> This  

code is fairly straightforward. It simply executes a loop as long as the  

service thread is still running. The code within the loop beeps the PC speaker,  

sleeps for one second, and then calls the service thread's <i>ProcessRequests</i> method. The call to <i>ProcessRequests</i> is vital. If you don't call <i>ProcessRequests</i>, your service will execute the loop once and then  

stop. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> This  

service is not very exciting. In fact, it's downright annoying when it's  

running. Still, it's a perfectly valid service and shows the simplest type of  

service you can write. What may not be obvious, though, is all the work being  

done behind the scenes by the VCL. The code for this service is available for  

download; see end of article for details. Load the project in C++Builder and  

build it. You can then proceed to the next step, installing the service. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Subheads>Installing  

the Service</p>  

  

<p class=BodyText> A  

service must be installed after it is built. Installing a service registers the  

service with the SCM. The SCM, in turn, adds the service's configuration  

information to the registry. Figure 3 shows the registry key for BeepService. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<img width=250  

 height=130 src="images/cb199910NT0602_f_image002.gif" tppabs="http://www.cbuilderzine.com/features/1999/10/cb199910NT0602_f/cb199910NT0602_f_image002.gif" align=left> <br  

style='mso-ignore:vglayout' clear=ALL>  

<b>Figure 3:</b> The registry key created by the  

SCM when it registered BeepService.  

  

<p class=BodyText> &nbsp; </p>  

  

<br clear=all>  

  

<p class=BodyText> To  

install a service, run the service application from the command line using the  

INSTALL switch: </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Code><span class=Code>beepsrvc  

/install</span></p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> After a  

second or so, you will see a message box that reads as follows: </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Code><span class=Code>Service  

installed successfully</span></p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> If the  

service didn't install successfully, you'll need to check your code to see if  

you've missed anything. If you have loaded BeepService from the accompanying  

download, it will install without error. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> Note: NT  

services are, naturally, for use with the NT operating system. If you attempt  

to run a stock service application from Win9x, it will return without doing  

anything at all. Technically speaking, it is possible to run services in Win9x  

using various tricks and utilities. On the other hand, the Win9x operating  

systems certainly do not have full support for services and I do not attempt to  

cover the use of services on those platforms in this article series. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> To  

uninstall a service, first stop the service if it is started. (I discuss  

controlling services in the next section.) Run the service application again,  

this time with the UNINSTALL switch: </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Code><span class=Code>beepsrvc  

/uninstall</span></p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> A  

message box will tell you that the service was successfully uninstalled.  

Understand that uninstalling a running service does not terminate the service;  

it only removes the service from the registry. For that reason, you should stop  

the service before uninstalling the service. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> Note:  

While developing a service, you will continually be in a cycle of changing  

code, compiling, and running the service to test the results of your code  

changes. It is not necessary to uninstall the service each time you build the  

service application from C++Builder. It is, however, necessary for you to stop  

the service before building the service application. Failure to stop the  

service prior to building the service application will result in a C++Builder  

linker error message that reads as follows: </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Code><span class=Code>Could not open  

D:\Services\BeepSrvc.exe (program still running?). </span></p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> You will  

know that you need to stop the service before continuing if you get this error  

message when building the service application. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> I  

usually keep a command prompt box open when developing a service. Once I have  

typed the install or uninstall command, I can easily install or uninstall a  

service by taking advantage of NT's capability to recall commands typed at the  

command prompt (using the up and down arrows on the keyboard). </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Subheads>Testing the  

Service</p>  

  

<p class=BodyText> If the  

service installed successfully, open the SCP from the Control Panel and you  

will see the service listed among the other installed services. You will see  

the service name, BeepService, and the <i>Startup</i> type listed as <i>Automatic</i>.  

The Status column will be blank, indicating that the service is stopped. Even  

though the service is configured to start automatically, this doesn't happen  

until the system is restarted. You will have to reboot NT to test your  

service's auto-start capability. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> To start  

BeepService, click the Start button on the SCP. NT will start the service and you will hear  

the PC speaker beep every second. Figure 4 shows the SCP when starting  

BeepService. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Captions> <img width=250  

 height=139 src="images/cb199910NT0602_f_image004.gif" tppabs="http://www.cbuilderzine.com/features/1999/10/cb199910NT0602_f/cb199910NT0602_f_image004.gif" align=left> <br  

style='mso-ignore:vglayout' clear=ALL>  

<b>Figure 4:</b> The SCP will start BeepService  

when you click the <b>Start </b>button. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<br clear=all>  

  

<p class=BodyText> After  

the service has started, the Status column in the SCP will show Started. Test the service's capability to  

pause by clicking the Pause button. Restart the service by clicking the Continue  

button. Stop the  

service and restart it. You will notice that the service responds to the  

service control requests automatically. It's impossible to overstate the  

benefits of writing services with C++Builder. If you've ever had to write a  

service using the API, you can appreciate all the work that the VCL is doing in  

the background. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=BodyText> Most of  

the time, it's convenient to simply use the SCP to start, stop, pause,  

continue, or configure your service. One annoyance of the SCP is that it has no  

associated taskbar button. This means that you can't easily find the SCP when  

it gets lost behind other windows. Further, the SCP has no capability to  

refresh its display. If the SCP is already running and you double-click its  

icon in the Control Panel, NT simply brings the SCP to the top - it won't  

update its display. Say, for example, that you have the SCP open and you  

install your service from a command prompt box. If you switch back to the SCP,  

your service won't show up in the list of installed services. You have to close  

the SCP and then reopen it by double-clicking the services icon in the Control  

Panel. If for some reason your service doesn't show up when installed, or  

doesn't disappear when uninstalled, remember to close the SCP and reopen it. </p>  

  

<p class=BodyText> &nbsp; </p>  

  

<p class=Subheads>Using a  

⌨️ 快捷键说明

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