Menulis Fungsi ServiceMain
Fungsi SvcMain dalam contoh berikut adalah fungsi ServiceMain untuk layanan contoh. SvcMain memiliki akses ke argumen baris perintah untuk layanan dengan cara fungsi utama aplikasi konsol. Parameter pertama berisi jumlah argumen yang diteruskan ke layanan di parameter kedua. Akan selalu ada setidaknya satu argumen. Parameter kedua adalah penunjuk ke array penunjuk string. Item pertama dalam array selalu merupakan nama layanan.
Fungsi SvcMain pertama-tama memanggil fungsi RegisterServiceCtrlHandler untuk mendaftarkan fungsi SvcCtrlHandler sebagai fungsi Handler layanan dan memulai inisialisasi. RegisterServiceCtrlHandler harus menjadi fungsi nonfailing pertama di ServiceMain sehingga layanan dapat menggunakan handel status yang dikembalikan oleh fungsi ini untuk memanggil SetServiceStatus dengan status SERVICE_STOPPED jika terjadi kesalahan.
Selanjutnya, fungsi SvcMain memanggil fungsi ReportSvcStatus untuk menunjukkan bahwa status awalnya SERVICE_START_PENDING. Saat layanan dalam keadaan ini, tidak ada kontrol yang diterima. Untuk menyederhanakan logika layanan, disarankan agar layanan tidak menerima kontrol apa pun saat melakukan inisialisasinya.
Terakhir, fungsi SvcMain memanggil fungsi SvcInit untuk melakukan inisialisasi khusus layanan dan memulai pekerjaan yang akan dilakukan oleh layanan.
Fungsi inisialisasi sampel, SvcInit, adalah contoh yang sangat sederhana; ini tidak melakukan tugas inisialisasi yang lebih kompleks seperti membuat utas tambahan. Ini membuat peristiwa yang dapat disinyal oleh penangan kontrol layanan untuk menunjukkan bahwa layanan harus berhenti, lalu memanggil ReportSvcStatus untuk menunjukkan bahwa layanan telah memasuki status SERVICE_RUNNING. Pada titik ini, layanan telah menyelesaikan inisialisasinya dan siap untuk menerima kontrol. Untuk performa sistem terbaik, aplikasi Anda harus memasuki status berjalan dalam 25-100 milidetik.
Karena layanan sampel ini tidak menyelesaikan tugas nyata apa pun, SvcInit hanya menunggu peristiwa penghentian layanan disinyalkan dengan memanggil fungsi WaitForSingleObject , memanggil ReportSvcStatus untuk menunjukkan bahwa layanan telah memasuki status SERVICE_STOPPED, dan mengembalikan. (Perhatikan bahwa penting bagi fungsi untuk kembali, daripada memanggil fungsi ExitThread , karena mengembalikan memungkinkan pembersihan memori yang dialokasikan untuk argumen.) Anda dapat melakukan tugas pembersihan tambahan dengan menggunakan fungsi RegisterWaitForSingleObject alih-alih WaitForSingleObject. Utas yang menjalankan fungsi ServiceMain berakhir, tetapi layanan itu sendiri terus berjalan. Saat handler kontrol layanan memberi sinyal peristiwa, utas dari kumpulan utas menjalankan panggilan balik Anda untuk melakukan pembersihan tambahan, termasuk mengatur status ke SERVICE_STOPPED.
Perhatikan bahwa contoh ini menggunakan SvcReportEvent untuk menulis peristiwa kesalahan ke log peristiwa. Untuk kode sumber untuk SvcReportEvent, lihat Svc.cpp. Untuk contoh fungsi handler kontrol, lihat Menulis Fungsi Handler Kontrol.
Definisi global berikut digunakan dalam sampel ini.
#define SVCNAME TEXT("SvcName")
SERVICE_STATUS gSvcStatus;
SERVICE_STATUS_HANDLE gSvcStatusHandle;
HANDLE ghSvcStopEvent = NULL;
Fragmen sampel berikut diambil dari sampel layanan lengkap.
//
// 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 );
}
Topik terkait