荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Jobs (温少), 信区: Visual
标  题: New Features of Service Applications for Microsoft Windows 2000
发信站: BBS 荔园晨风站 (Mon Nov 29 17:06:42 1999), 站内信件



New Features of Service Applications for Microsoft Windows 2000
Donis Marshall
Gearhead Press

August 1999

Summary: In Microsoft? Windows? 2000, enhancements to the service model
represent an important step in the evolution of services. This article details
many exciting new features with several code examples that can be applied to
your service. (9 printed pages)

Introduction
In Microsoft? Windows? 2000, enhancements to the service model represent an
important step in the evolution of services. Many exciting new features
include:

For more efficient coding, a better way to share service handlers has been
introduced.


Developing a well-behaved service application is much easier with the extended
control codes.


Expanded error handling promotes better management and control of services.


Some new service functions and structures provide additional capabilities:
EnumServiceStatusEx, QueryServiceConfig2, ChangeServiceConfig2, and
RegisterServiceCtrlHandlerEx.
This article details these features with several code examples that can be
applied to your service.

Application Development Refined
Windows 2000 is the harbinger of innovative new technologies and represents a
refinement in the science of developing Windows applications. The methodology
of writing a service application remains intact. However, specific changes in
the Platform SDK as related to services are compelling and merit examination.
These changes affect the three primary components of the service architecture:
service applications, service control programs (SCPs), and the service control
manager (SCM).

This article focuses on changes with Microsoft Win32? services. Device drivers
and net services are not considered.

In the Win32 environment, services are background processes that persist across
logon sessions. Services usually do not present a graphical user interface (GUI)
, and are managed by the service control manager. The SCM, which is a remote
procedure call (RPC) server, supports local or remote management of a service.
You can construct applications that indirectly control services through the SCM
with service functions exported from advapi32.dll. This type of application is
called an SCP. Typically, a user administers a service through an SCP. There
are both generic and product-specific SCPs.

Although a service application is a functional Win32 application, it should be
started solely by the SCM and never by the user. The SCM maintains a list of
services and collateral data in the registry. This information is essential for
launching a service. Auto-start services are started when the operating system
boots. Demand-start services are started on demand by users through an SCP. The
services database resides in the registry at HKEY_LOCAL_MACHINE \ SYSTEM \
CurrentControlSet \ Services.

Services are not supported in Windows 98 or Windows 95.

New Features of Service Applications
A service executable can host one or more services梕ach of which is spawned in
a separate thread. Then, a service designates a handler to catch
service-control messages sent by the SCM. For this reason, incoming
service-control messages are routed to the handler by the service-control
dispatcher, which runs as a thread inside of the service executable. A handler
will respond to the message.

The Service controller maintains a count of the running services in each
service executable. When the count drops to zero, it tells the service control
dispatcher to exit, and the service application closes shortly thereafter. The
dispatcher and any handlers execute on the same thread. However, services and
representative handlers run on different threads.

Once a service is started, the service is given 82 seconds to register a
handler and call SetServiceStatus for the first time. In Windows 2000, a
service designates a handler with the RegisterServiceCtrlHandlerEx function.

SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerEx(LPCTSTR lpServiceName,
LPHANDLER_FUNCTION_EX lpHandlerProc,   LPVOID lpContext )

This function extends RegisterServiceCtrlHandler and has a single additional
parameter條pContext. The last parameter is 32 bits of programmer-defined data.
It is useful when services share the same handler. Within the handler,
lpContext can help identify the service context. In the following scenario,
lpContext is an integral value naming a service [Code 1].

Code 1
// In ServiceA
RegisterServiceCtrlHandler("ServiceA", HandlerEx, (LPVOID) 1);
?

// In ServiceB
RegisterServiceCtrlHandler("ServiceB", HandlerEx, (LPVOID) 2);
?

// In Handler
DWORD WINAPI HandlerEx(  DWORD dwControl,  DWORD dwEventType,
     LPVOID lpEventData, LPVOID lpContext)
{
   if( ((int) lpContext) == 1 )
   {
      // ServiceA specific code
   }
   else
   {
      // ServiceB specific code
   }
}

In addition, lpContext can be a pointer to data shared between a service and
its companion handler.

With RegisterServiceCtrlHandlerEx, the second parameter HandlerEx replaces
Handler.

DWORD WINAPI HandlerEx(  DWORD dwControl,  DWORD dwEventType,
     LPVOID lpEventData, LPVOID lpContext)

The first parameter is identical to the corresponding parameter of Handler. It
is the service control message forwarded by the service control dispatcher.

The dwEventType, lpEventData, and lpContext parameters are new to Windows 2000.
In addition, the return type has changed. The dwEventType and lpEventData
parameters are applicable to a subset of service control messages that track
changes in the state of system hardware or configuration. The dwEventType and
1pEventData parameters are not relevant for the other service control messages.

The lpContext member is the optional data transmitted from
RegisterServiceCtrlHandlerEx directly to the handler. The new handler returns
an error code梟ot void. If the service control message is handled, NO_ERROR is
returned. Otherwise, ERROR_CALL_NOT_IMPLEMENTED is returned. If the message is
related to the hardware state or status, returning a Win32 error code other
than NO_ERROR will reject the event.

In Windows 2000, both Handler and HandlerEx can receive the new service control
message that notifies a service of changes to its parameters (stored at
HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Services \ service name \
Parameters). If relevant, the service should reread its parameters.

SERVICE_CONTROL_PARAMCHANGE

In addition, HandlerEx gets extra messages unique to itself. These messages
help a service react appropriately to changes in the hardware configuration or
the state of the machine. These service control messages are:

   SERVICE_CONTROL_HARDWAREPROFILECHANGE
   SERVICE_CONTROL_DEVICEEVENT
   SERVICE_CONTROL_POWEREVENT

To accept these new messages, the appropriate flags must be submitted using
SetServiceStatus. In the SERVICE_STATUS structure, the dwControlsAccepted
member should be updated to reflect the desired messages. The bitwise flags are:

   SERVICE_ACCEPT_PARAMCHANGE
   SERVICE_ACCEPT_HARDWAREPROFILECHANGE
   SERVICE_ACCEPT_POWEREVENT

In addition, a service registers for SERVICE_CONTROL_DEVICEEVENT notifications
by calling the RegisterDeviceNotification function.

With the exception of SERVICE_CONTROL_PARAMCHANGE, an SCP cannot send these new
messages with the function ControlService.

When the hardware profile of a system is altered, a
SERVICE_CONTROL_HARDWAREPROFILECHANGE is sent to the service handler. Hardware
profiles are created with the System applet in the Service Control Panel. Based
on the new hardware configuration, the service may modify its ongoing
activities.

SERVICE_CONTROL_DEVICEEVENT is the service equivalent to the Win32 message
WM_DEVICEEVENT. Inserting, removing, or the transformation of a hardware device
triggers this event. With this message, the dwEventType parameter of the
handler is the event identifier. This is similar to the WPARAM of
WM_DEVICEEVENT. lpEventData is optional event and data equivalent to the LPARAM
of WM_DEVICEEVENT.

A service can begin immediately using any new devices. Of course, if a device
is no longer available, the service should stop using it. A power event
announces a power modulation or vacillation. SERVICE_ACCEPT_POWEREVENT is the
service equivalent of the WM_POWERBROADCAST message; dwEventType is the power
event identifier, and lpEventData is optional data [Code 2]. This is the WPARAM
and LPARAM of WM_POWERBROADCAST, respectively.

Power events afford an opportunity to cache or retrieve data as the result of
suspend or resume events.

Code 2
DWORD WINAPI ServiceHandler( DWORD fdwControl,    DWORD dwEventType,
   LPVOID lpEventData, LPVOID lpContext )
{

   // Local variables.

   static DWORD CachedState;
   LPEVENTINFO pEventInfo;
   DWORD dwBuffer;

   // Do not replicate current state.
   // Controls codes greater than 127 are programmer
   //      defined service control codes.

   if(( CachedState == fdwControl) && ( fdwControl < 128))
      return NO_ERROR;

   // Switch on service control message.
   switch(fdwControl)
   {

      case SERVICE_CONTROL_POWEREVENT:
      {
         switch((int) dwEventType)
            {
            case PBT_APMPOWERSTATUSCHANGE:
               // handle event
               return NO_ERROR;
            case PBT_APMSUSPEND:
               // handle event
               return NO_ERROR;

            // case PBT_WhatEver and so on.
            }
         }
         break;
   ?.

Service Control Program Enhancements
In Windows 2000, the SCM monitors and tallies service failures. A service
failure occurs when a service closes without reporting a stop event. You can
assign specific behavior to the nth failure of a service.

ChangeServiceConfig2 is a polymorphic function that is used to set services
failure actions or description. ChangeServiceConfig2 is not an extension of
ChangeServiceConfig.

BOOL ChangeServiceConfig2(  SC_HANDLE hService, DWORD dwInfoLevel,
LPVOID lpInfo )

The first parameter is a service handle. Open the service handle with
OpenService or CreateService. Access flags on the service handle should include
SERVICE_CHANGE_CONFIG.

To set the failure actions of a service, the second parameter should be
SERVICE_CONFIG_FAILURE_ACTIONS. With this flag, the last parameter, lpInfo, is
treated as a pointer to a SERVICE_FAILURE_ACTIONS structure.

SERVICE_FAILURE_ACTIONS
DWORD       dwResetPeriod;
LPTSTR       lpRebootMsg;
LPTSTR       lpCommand;
DWORD       cActions;
SC_ACTION *   lpsaActions;

The SCM maintains the count of service failures from the last time the system
was booted. In milliseconds, dwResetPeriod establishes a period for resetting
the count if no service failure has occurred. If dwResetPeriod is INFINITE, the
count is never reset.

An action or command can be associated with a service failure. The lpCommand
element is a string reflecting the command line of a chosen operation.
Internally, ChangeConfig2 uses CreateProcessAsUser to execute the specified
command line.

The member, cActions, is the number of failure events being initialized.

The SC_ACTION structure is a prescription for handling a service failure. There
are four choices:

Reboot the system upon service failure.


Restart the service when the service fails.


Execute a command if the service fails.


No reaction when the service fails.
The SC_ACTION structure is:

SC_ACTION
SC_ACTION_TYPE     Type;
DWORD              Delay;

Type is the requested action: SC_ACTION_REBOOT, SC_ACTION_RESTART,
SC_ACTION_RUN_COMMAND, and SC_ACTION_NONE. Delay sets a wait time (in
milliseconds) before the stipulated action is executed.

For SERVICE_FAILURE_ACTIONS, create an array of SC_ACTION structures. Actions
refer to the number of elements in this array. Initialize the SC_ACTION pointer
of SERVICE_FAILURE_ACTIONS with the array pointer. The first element of the
array sets event handling for the first failure; the next element establishes
handling for the second failure, and so on.

To give a service a description, set the dwInfoLevel parameter of
ChangeConfigService2 to SERVICE_CONFIG_DESCRIPTION. With this flag, the last
parameter (lpInfo) is a pointer to SERVICE_DESCRIPTION. SERVICE_DESCRIPTION has
a single element, lpDescription [Code 3].

Code 3
SERVICE_DESCRIPTION sd;
sd.lpDescription="Service Two ( Generic Description )";
hService=OpenService(hSCM, "Service Two", SERVICE_ALL_ACCESS);
ChangeServiceConfig2(hService,
                               SERVICE_CONFIG_DESCRIPTION,
                     &sd))
CloseServiceHandle(hService);

Conversely, to query the service's failure actions or description, use
QueryServiceConfig2.

BOOL QueryServiceConfig2( SC_HANDLE hService, DWORD dwInfoLevelLPBYTE lpBuffer,
    DWORD cbBufSize, LPDWORD pcbBytesNeeded)

Initialize the service handle with OpenService or CreateService. Depending on
the desired data, the information level is SERVICE_CONFIG_DESCRIPTION or
SERVICE_FAILURE_ACTIONS. The next parameter is an out buffer or pointer to
SERVICE_DESCRIPTION or SERVICE_FAILURE_ACTIONS, respectively. In cbBufSize,
store the size of the buffer. When the call is made, the buffer may not be
sufficiently large. When this occurs, pcbBytesNeeded will contain the number of
bytes required to complete this request, and GetLastError will return
ERROR_INSUFFICIENT_BUFFER.

The SERVICE_CONFIG_DESCRIPTION and SERVICE_FAILURE_ACTIONS structures contain
pointers to variable length blocks of memory. QueryServiceConfig2 appends this
memory to the end of the structure. You must provide enough memory for the
appropriate structure and the appended data. However, this can be difficult to
calculate. One strategy to ascertain the appropriate size of the buffer is to
invoke QueryServiceConfig2 twice [Code 4]. Call QueryServiceConfig2 with a zero
length buffer to determine the size, then create a buffer of the required size,
and finally invoke QueryServiceConfig2 again to gather the data.

Code 4
DWORD dwSize;
LPSERVICE_FAILURE_ACTIONS pSFA=NULL;

hService=OpenService(hSCM, "Service Two", SERVICE_ALL_ACCESS);
QueryServiceConfig2(  hService, SERVICE_CONFIG_FAILURE_ACTIONS,
   NULL, 10, &dwSize);
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
   pSFA=(LPSERVICE_FAILURE_ACTIONS) new BYTE[dwSize];
   QueryServiceConfig2(  hService,
SERVICE_CONFIG_FAILURE_ACTIONS,
      (LPBYTE) pSFA, dwSize, &dwSize);
}

// Process configuration information.

EnumServiceStatusEx supersedes EnumServiceStatus. It has an additional
parameter for enumerating services within a group.

BOOL EnumServicesStatusEx( SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel,
       DWORD dwServiceType, DWORD dwServiceState, LPBYTE lpServices,
DWORD cbBufSize, LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned,
      LPDWORD lpResumeHandle, LPCTSTR pszGroupName)

The last parameter is the name of the service group to be enumerated. If it is
an empty string, all services not in a group will be enumerated. If NULL, all
services of dwServiceType will be enumerated. As you did with
QueryServiceConfig2, invoke EnumServiceStatusEx twice first to determine size
and then to receive the information.

Conclusion
The changes in services reflect the practical necessities of services in a
real-world environment. These enhancements will be invaluable to service
developers as they create solutions for the new millennium.

To focus on topics specific to this article, the program code of this article
does not include error handling. When replicating this code, be sure to add the
appropriate error handling.

? 1999 Microsoft Corporation. All rights reserved. Terms of use.

--
☆ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: bbs@192.168.11.111]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店