Services

1 概述

1服務(wù)程序遵循Service Control Manager(SCM)的接口規(guī)則。 啟動(dòng)方式由3種:1 系統(tǒng)啟動(dòng)時(shí)自動(dòng)啟動(dòng);2 通過服務(wù)控制面板;3 通過使用服務(wù)函數(shù)。2服務(wù)可以在沒有用戶登錄到系統(tǒng)的情況下運(yùn)行。

2 驅(qū)動(dòng)服務(wù)驅(qū)動(dòng)服務(wù)遵循設(shè)備驅(qū)動(dòng)協(xié)議,它與服務(wù)程序類似,但是不與SCM交互。

3 The SCM processes service control notifications in a serial fashion

4 The default security descriptor allows the LocalSystem account, and members of the Administrators and Power Users groups to stop and start services.

 

2 服務(wù)在Win7中的新特性

1 可以注冊(cè)一個(gè)服務(wù),在一個(gè)特定事件發(fā)生時(shí)啟動(dòng)或者停止服務(wù)。

更新的函數(shù)

ChangeServiceConfig

Changes the configuration parameters of a service. This function supports managed service accounts and virtual accounts. For more information, see Service Accounts Step-by-Step Guide.

ChangeServiceConfig2

Changes the optional configuration parameters of a service. This function supports new configuration information levels for processor groups and service trigger events.

CreateService

Creates a service object and adds it to the specified service control manager database. This function supports managed service accounts and virtual accounts. For more information, see Service Accounts Step-by-Step Guide.

HandlerEx

An application-defined callback function used with the RegisterServiceCtrlHandlerEx function. This callback function supports new extended control codes for system time changes and service trigger events.

QueryServiceConfig2

Retrieves the optional configuration parameters of a service. This function supports new configuration information levels for processor groups and service trigger events.

SetServiceStatus

Updates the service control manager's status information for the calling service. This function supports new extended control codes for system time changes and service trigger events.

 

新的結(jié)構(gòu)

SERVICE_TIMECHANGE_INFO

Contains system time change settings.

SERVICE_TRIGGER

Represents a service trigger event.

SERVICE_TRIGGER_INFO

Contains trigger event information for a service.

SERVICE_TRIGGER_SPECIFIC_DATA_ITEM

Contains trigger-specific data for a service trigger event.

Service Changes for Windows Vista

 

為了提高性能、可靠性、安全性、可管理性等,在Vista之后,服務(wù)提供了很多增強(qiáng)的特性。

 

Session 0 Isolation

服務(wù)總是運(yùn)行在Session 0,在Vista之前,第一個(gè)用戶也是運(yùn)行在Session0,在Vista之后,第一個(gè)用戶運(yùn)行在Session1,第二個(gè)用戶運(yùn)行在Session2 等等,這樣用戶程序和服務(wù)就始終運(yùn)行在不同的Session上。Session 0 不支持與用戶交互的進(jìn)程。這就意味著Service不能向應(yīng)用程序發(fā)送消息,應(yīng)用程序也不能像Service發(fā)送消息。除此之外,Service還不能顯示GUI,如對(duì)話框,但是Service可以使用WTSSendMessage 函數(shù)在另一個(gè)Session中顯示對(duì)話框。

Delayed AutoStart 在系統(tǒng)啟動(dòng)的一小段時(shí)間(shortly after)內(nèi)啟動(dòng)服務(wù)。

Failure Detection and Recovery:如果服務(wù)失敗,SCM可以執(zhí)行失敗action,如重啟服務(wù)。

Preshutdown Notifications:是服務(wù)有足夠的時(shí)間來優(yōu)雅的關(guān)閉。

Restricted Network Acess

Running with Least Privilage

 

關(guān)于服務(wù)

SCM維護(hù)者已安裝的服務(wù)和驅(qū)動(dòng)服務(wù)的數(shù)據(jù)庫(kù),并且提供了統(tǒng)一的安全的控制它們的方法。數(shù)據(jù)庫(kù)信息包括每個(gè)服務(wù)如何被啟動(dòng)。

下面類型的程序使用SCM提供的函數(shù):

服務(wù)程序(Service Program):一個(gè)為一個(gè)或者多個(gè)服務(wù)提供可執(zhí)行代碼的程序。服務(wù)程序使用連接到SCM的函數(shù)以及發(fā)送狀態(tài)信息給SCM的函數(shù)。

服務(wù)配置程序(Service configuration program):一個(gè)查詢和修改服務(wù)數(shù)據(jù)庫(kù)的程序。服務(wù)配置程序使用打開數(shù)據(jù)庫(kù)的函數(shù),在數(shù)據(jù)庫(kù)中安裝和刪除服務(wù),對(duì)安裝的服務(wù)查詢和修改配置參數(shù),安全參數(shù)。服務(wù)配置程序管理服務(wù)以及驅(qū)動(dòng)服務(wù)。

服務(wù)控制程序(Service Control Program):一個(gè)啟動(dòng)并控制服務(wù)以及驅(qū)動(dòng)服務(wù)的程序。服務(wù)控制程序使用發(fā)送請(qǐng)求到SCM的函數(shù)。

Service Control Manager(服務(wù)控制管理器)

1 系統(tǒng)啟動(dòng)時(shí)啟動(dòng);它是一個(gè)RPC (Remote procedure call) 服務(wù)器。所以服務(wù)配置和服務(wù)控制程序可以在遠(yuǎn)程機(jī)器上管理服務(wù)。

提供接口功能:

管理安裝服務(wù)的數(shù)據(jù)庫(kù);

啟動(dòng)服務(wù)(系統(tǒng)啟動(dòng)時(shí),或者需要時(shí))

枚舉安裝的服務(wù)

為運(yùn)行的服務(wù)維護(hù)狀態(tài)信息

傳輸控制請(qǐng)求(control request)給正在運(yùn)行的服務(wù)

鎖定和解鎖服務(wù)數(shù)據(jù)庫(kù)。

Database of installed service

在注冊(cè)表中維護(hù)著已安裝的服務(wù)列表。注冊(cè)表如下

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services.

這個(gè)鍵值為每一個(gè)安裝的服務(wù)包含一個(gè)子鍵,子鍵的名字就是服務(wù)名。

Database又叫作ServiceActive databse或者SCM database。你必須使用SCM提供的函數(shù),而不能直接修改databse,即不能直接修改注冊(cè)表。

自動(dòng)啟動(dòng)服務(wù)

在系統(tǒng)啟動(dòng)的時(shí)候,SCM將啟動(dòng)所有自啟動(dòng)的服務(wù)以及它們依賴的服務(wù)。

啟動(dòng)順序:

1 按加載啟動(dòng)組列表中的順序;這個(gè)信息保存在ServiceGroupOrder值中,

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

2 GroupOrderList

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

3 每個(gè)服務(wù)的依賴列表

當(dāng)啟動(dòng)完成后,系統(tǒng)執(zhí)行啟動(dòng)認(rèn)證程序(boot verification program)根據(jù)BootVerificationProgram

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control.

默認(rèn)情況下,這個(gè)值是沒有設(shè)置的。你可以提供程序來檢測(cè)系統(tǒng),調(diào)用NotifyBootConfigStatus通知SCM,報(bào)告boot 狀態(tài)。

在成功重啟后,系統(tǒng)會(huì)將組冊(cè)表復(fù)制一份到下面目錄下last-known-good (LKG) configuration

HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Services

按需啟動(dòng)服務(wù)

當(dāng)服務(wù)啟動(dòng)之后,SCM執(zhí)行下列步驟:

獲取存儲(chǔ)在數(shù)據(jù)庫(kù)中的帳戶信息

登錄到服務(wù)帳戶

加載用戶配置

在暫停狀態(tài)下創(chuàng)建服務(wù)

給進(jìn)程分配一個(gè)Logontoken

允許進(jìn)程執(zhí)行

Service Record List

由于每個(gè)服務(wù)實(shí)體是從注冊(cè)表數(shù)據(jù)庫(kù)中讀取的,因此SCM為每個(gè)服務(wù)創(chuàng)建了一個(gè)Service Record

一個(gè)Service Record包括:

服務(wù)名

啟動(dòng)類型

服務(wù)狀態(tài)(SERVICE_STATUS結(jié)構(gòu))

指向依賴服務(wù)列表的指針

服務(wù)在安裝的時(shí)候用戶名和密碼是指定好的。SCM在注冊(cè)表中存放用戶名,在Local Security AuthorityLSA)中存放密碼。

SCM保存兩份用戶密碼。一個(gè)當(dāng)前密碼和一個(gè)備份密碼。在服務(wù)第一次安裝的時(shí)候使用當(dāng)前密碼,備份密碼是未初始化的。當(dāng)用當(dāng)前密碼運(yùn)行服務(wù)成功后,才會(huì)將當(dāng)前密碼寫入到備份密碼。SCM在收到服務(wù)狀態(tài)通知后更新服務(wù)狀態(tài)。

驅(qū)動(dòng)服務(wù)的狀態(tài)是通過查詢IO系統(tǒng)獲得的,而不是通過狀態(tài)通知,這點(diǎn)是與Service不同的。

SCM Handles

SCM支持句柄(Handle)來訪問下面的對(duì)象。

已安裝的服務(wù)的數(shù)據(jù)庫(kù):用SCManager object來表示

服務(wù):由一個(gè)安裝的服務(wù)代表服務(wù)對(duì)象。

數(shù)據(jù)庫(kù)鎖

Service Programs服務(wù)程序

Main函數(shù):

調(diào)用StartServiceCtrlDispatcher函數(shù)連接到SCM并啟動(dòng)control dispatcher線程。Control dispatcher線程循環(huán)loop,等待在dispatch table中指定的服務(wù)的請(qǐng)求。

例子:

void __cdecl _tmain(int argc, TCHAR *argv[])

{

    // If command-line parameter is "install", install the service.

    // Otherwise, the service is probably being started by the SCM.

 

    if( lstrcmpi( argv[1], TEXT("install")) == 0 )

    {

        SvcInstall();

        return;

    }

 

    // TO_DO: Add any additional services for the process to this table.

    SERVICE_TABLE_ENTRY DispatchTable[] =

    {

        { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },

        { NULL, NULL }

    };

 

    // This call returns when the service has stopped.

    // The process should simply terminate when the call returns.

 

    if (!StartServiceCtrlDispatcher( DispatchTable ))

    {

        SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));

    }

}

ServiceMain函數(shù):

首先調(diào)用RegisterServiceCtrlHandler函數(shù)來注冊(cè)SvcCtrHandler函數(shù)作為服務(wù)的處理函數(shù),然后開始初始化。

VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )

{

    // Register the handler function for the service

 

    gSvcStatusHandle = RegisterServiceCtrlHandler(

        SVCNAME,

        SvcCtrlHandler);

 

    if( !gSvcStatusHandle )

    {

        SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));

        return;

    }

 

    // These SERVICE_STATUS members remain as set here

 

    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;

    gSvcStatus.dwServiceSpecificExitCode = 0;   

 

    // Report initial status to the SCM

 

    ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );

 

    // Perform service-specific initialization and work.

 

    SvcInit( dwArgc, lpszArgv );

}

 

//

// Purpose:

//   The service code

//

// Parameters:

//   dwArgc - Number of arguments in the lpszArgv array

//   lpszArgv - Array of strings. The first string is the name of

//     the service and subsequent strings are passed by the process

//     that called the StartService function to start the service.

//

// Return value:

//   None

//

VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)

{

    // TO_DO: Declare and set any required variables.

    //   Be sure to periodically call ReportSvcStatus() with

    //   SERVICE_START_PENDING. If initialization fails, call

    //   ReportSvcStatus with SERVICE_STOPPED.

 

    // Create an event. The control handler function, SvcCtrlHandler,

    // signals this event when it receives the stop control code.

 

    ghSvcStopEvent = CreateEvent(

                         NULL,    // default security attributes

                         TRUE,    // manual reset event

                         FALSE,   // not signaled

                         NULL);   // no name

 

    if ( ghSvcStopEvent == NULL)

    {

        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );

        return;

    }

 

    // Report running status when initialization is complete.

 

    ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );

 

    // TO_DO: Perform work until service stops.

 

    while(1)

    {

        // Check whether to stop the service.

 

        WaitForSingleObject(ghSvcStopEvent, INFINITE);

 

        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );

        return;

    }

}

 

//

// Purpose:

//   Sets the current service status and reports it to the SCM.

//

// Parameters:

//   dwCurrentState - The current state (see SERVICE_STATUS)

//   dwWin32ExitCode - The system error code

//   dwWaitHint - Estimated time for pending operation,

//     in milliseconds

//

// Return value:

//   None

//

VOID ReportSvcStatus( DWORD dwCurrentState,

                      DWORD dwWin32ExitCode,

                      DWORD dwWaitHint)

{

    static DWORD dwCheckPoint = 1;

 

    // Fill in the SERVICE_STATUS structure.

 

    gSvcStatus.dwCurrentState = dwCurrentState;

    gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;

    gSvcStatus.dwWaitHint = dwWaitHint;

 

    if (dwCurrentState == SERVICE_START_PENDING)

        gSvcStatus.dwControlsAccepted = 0;

    else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

 

    if ( (dwCurrentState == SERVICE_RUNNING) ||

           (dwCurrentState == SERVICE_STOPPED) )

        gSvcStatus.dwCheckPoint = 0;

    else gSvcStatus.dwCheckPoint = dwCheckPoint++;

 

    // Report the status of the service to the SCM.

    SetServiceStatus( gSvcStatusHandle, &gSvcStatus );

}

 

Control Handler函數(shù):

該函數(shù)是由dispatcher thread調(diào)用的,它處理在OpCode參數(shù)中傳進(jìn)來的控制碼,然后調(diào)用ReportSvcStatus函數(shù)來更新服務(wù)狀態(tài)。當(dāng)Handler收到控制碼時(shí),只有當(dāng)收到的控制碼引起服務(wù)狀態(tài)變化時(shí)才報(bào)告服務(wù)狀態(tài)。

VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )

{

   // Handle the requested control code.

 

   switch(dwCtrl)

  

      case SERVICE_CONTROL_STOP:

         ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);

 

         // Signal the service to stop.

 

         SetEvent(ghSvcStopEvent);

         ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);

        

         return;

 

      case SERVICE_CONTROL_INTERROGATE:

         break;

 

      default:

         break;

   }

  

}

Service Configuration Program Tasks服務(wù)配置程序的任務(wù)

安裝服務(wù)

刪除服務(wù)

改變服務(wù)配置

查詢服務(wù)配置

Service Control Program Tasks服務(wù)控制程序任務(wù)

啟動(dòng)服務(wù)

停止服務(wù)

改變一個(gè)服務(wù)的DACL

 

Service Functions

The following functions are used or implemented by services.

Function

Description

Handler

An application-defined callback function used with the RegisterServiceCtrlHandler function.

HandlerEx

An application-defined callback function used with the RegisterServiceCtrlHandlerEx function.

RegisterServiceCtrlHandler

Registers a function to handle service control requests.

RegisterServiceCtrlHandlerEx

Registers a function to handle extended service control requests.

ServiceMain

An application-defined function that serves as the starting point for a service.

SetServiceBits

Registers a service type with the service control manager and the Server service.

SetServiceStatus

Updates the service control manager's status information for the calling service.

StartServiceCtrlDispatcher

Connects the main thread of a service process to the service control manager.

 

The following functions are used by programs that control or configure services.

Function

Description

ChangeServiceConfig

Changes the configuration parameters of a service.

ChangeServiceConfig2

Changes the optional configuration parameters of a service.

CloseServiceHandle

Closes the specified handle to a service control manager object or a service object.

ControlService

Sends a control code to a service.

ControlServiceEx

Sends a control code to a service.

CreateService

Creates a service object and adds it to the specified service control manager database.

DeleteService

Marks the specified service for deletion from the service control manager database.

EnumDependentServices

Retrieves the name and status of each service that depends on the specified service.

EnumServicesStatusEx

Enumerates services in the specified service control manager database based on the specified information level.

GetServiceDisplayName

Retrieves the display name of the specified service.

GetServiceKeyName

Retrieves the service name of the specified service.

NotifyBootConfigStatus

Reports the boot status to the service control manager.

NotifyServiceStatusChange

Enables an application to receive notification when the specified service is created or deleted or when its status changes.

OpenSCManager

Establishes a connection to the service control manager on the specified computer and opens the specified service control manager database.

OpenService

Opens an existing service.

QueryServiceConfig

Retrieves the configuration parameters of the specified service.

QueryServiceConfig2

Retrieves the optional configuration parameters of the specified service.

QueryServiceObjectSecurity

Retrieves a copy of the security descriptor associated with a service object.

QueryServiceStatusEx

Retrieves the current status of the specified service based on the specified information level.

SetServiceObjectSecurity

Sets the security descriptor of a service object.

StartService

Starts a service.

Service Structures

The following structures are used with services: