Share via


撰寫 ServiceMain 函式

下列範例中的 SvcMain 函式是範例服務的 ServiceMain 函式。 SvcMain 能夠存取服務的命令列引數,其方式是主控台應用程式 的主要 功能。 第一個參數包含在第二個參數中傳遞至服務的引數數目。 一律至少有一個引數。 第二個參數是字串指標陣列的指標。 陣列中的第一個專案一律是服務名稱。

SvcMain 函式會先呼叫 RegisterServiceCtrlHandler 函式,將 SvcCtrlHandler 函式註冊為服務的 Handler 函式,並開始初始化。 RegisterServiceCtrlHandler 應該是 ServiceMain 中的第一個非Failing 函式,如此一來,如果發生錯誤,服務可以使用此函式傳回的狀態控制碼來呼叫 SetServiceStatus 與SERVICE_STOPPED狀態。

接下來,SvcMain 函式會呼叫 ReportSvcStatus 函式,以指出其初始狀態為SERVICE_START_PENDING。 當服務處於此狀態時,不會接受任何控制項。 為了簡化服務的邏輯,建議您在服務執行初始化時,服務不接受任何控制項。

最後,SvcMain 函式會呼叫 SvcInit 函式來執行服務特定的初始化,並開始服務要執行的工作。

範例初始化函式 SvcInit 是非常簡單的範例;它不會執行更複雜的初始化工作,例如建立其他執行緒。 它會建立事件,服務控制處理常式可以發出訊號來指出服務應該停止,然後呼叫 ReportSvcStatus 來指出服務已進入SERVICE_RUNNING狀態。 此時,服務已完成其初始化,並準備好接受控制項。 為了獲得最佳系統效能,您的應用程式應該會在 25-100 毫秒內進入執行狀態。

由於此範例服務未完成任何實際工作,因此 SvcInit 只會藉由呼叫 WaitForSingleObject 函式來等候服務停止事件發出訊號、呼叫 ReportSvcStatus 以指出服務已進入SERVICE_STOPPED狀態,並傳回 。 (請注意,函數必須傳回,而不是呼叫 ExitThread 函式,因為傳回允許清除配置給 arguments.) 您可以使用 RegisterWaitForSingleObject 函式來執行額外的清除工作,而不是 WaitForSingleObject。 執行 ServiceMain 函式的執行緒會終止,但服務本身會繼續執行。 當服務控制處理常式發出事件的訊號時,執行緒集區中的執行緒會執行回呼來執行額外的清除,包括將狀態設定為 SERVICE_STOPPED。

請注意,此範例會使用 SvcReportEvent 將錯誤事件寫入事件記錄檔。 如需 SvcReportEvent 的原始程式碼,請參閱 Svc.cpp。 如需範例控制項處理常式函式,請參閱 撰寫控制項處理常式函式

此範例會使用下列全域定義。

#define SVCNAME TEXT("SvcName")

SERVICE_STATUS          gSvcStatus; 
SERVICE_STATUS_HANDLE   gSvcStatusHandle; 
HANDLE                  ghSvcStopEvent = NULL;

下列範例片段取自完整的服務範例。

//
// Purpose: 
//   Entry point for the service
//
// 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 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 );
}

ServiceMain 函式

完整服務範例