How to write NT Service in MSDN-> Platform SDK-> DLLS, Processes, And Threads-> Service is very clear, here I don't say much, I just say someone someone thinks in writing service Where you should pay attention to during the process.
0, when we start a service by the control panel or NET START command, Service Control Manager (SCM) gets the service-executable program name from the registry, then runs this program, gets the service from the portrait main method. The service_main method, then enter the service_main run.
A Service program contains minimal three parts, one is the main method, the usual work is to set the service_main method and handle the command line parameters (for example, perform other actions according to different parameters, like installing uninstall service, manual start stop service, etc.) One is the service_main method, the service program is written in this method, and is a ServiceCtrlHandler method. This method is set in service_main, which is used to process messages sent by SCM to Service, such as service stop, suspend, system Shutdown, etc.
1. Manually launch a service to call StartService in Service's main method, and StartService turns the program into the corresponding service_main based on Service's service_table_entry. The job you want to start when you start the service is written in Service_main. The usual mode is to set the service_start_pending after entering the service_main, then perform some initialization actions, then perform a thread or process in which the service is performed, and then set to service_running. Be sure that after starting the service, it must be guaranteed that the SERVICE status will be set to service_running in two minutes, otherwise the error will be reported.
2, stop a service is to call ControlService the main method of service in (hService, SERVICE_CONTROL_STOP, & ServStat) SERVICE_CONTROL_STOP send a message to the service will notify the Service Control Manager (SCM), SCM receive this message, do ServiceCtrlHandler in case SERVICE_CONTROL_STOP : Work within. Ending the action is usually not too long, because when shutdown, the system will give each service for about 20 seconds to clear the field (this time can be set in the registry)
3. Method for installing and uninstalling a service is to call the CreateService method and the deleteService method in the service's main method. Before the uninstall method, please determine if the service is running, if you want to stop the service first
Otherwise you can't delete it.
4. The method of setting the service state is to call SetServiceStatus, where the launch and stop action of the Write Service is to set its status, in the service_main and servicectrlhandler mentioned above. The method of querying the service status is queryServiceStatus. When the service is stopped, the ControlService method returns immediately after sending a message, so it is usually necessary to use While, Sleep and QueryServiceStatus to constantly query the status of the service until the SERVICE is used. For service_stopped. StartService is different from controlservice, not immediately returned, it will return until the code within Service_main is executed. 5, service_main Even if returned, Service's program process will not quit until the Status of Service is Service_Stopped, it will be terminated and exited.
6. When setting the service state, you can set the pop-up Message when the service is wrong in this state by specifying DWN32ExitCode and DWServicesPecIviceXitcode. However, only one error code can be set.
7, add a modification of the service using ChangeServiceConfig2.
8. By default, the service program cannot interact with the desktop, that is, the window cannot open. Set the service_interactive_process property through the ChangeServiceConfig function, or select "Allow Services and Desktop Interaction" by control panel, the service program can open the window. For example, using createProcess in the service creates a process, as long as STARTupinfo's WSHOWWINDOW and DWFLAGS sets sw_show and startf_useshowWindow, the process will run in a new window in the open.
9, whether it is set to set service_interactive_process, you can pop up MessageBox in the MessageBox method in Service. The first parameter of this function is specified as NULL, indicating that the parent window is not specified. Specify MB_DEFAULT_DESKTOP_ONLY or MB_SERVICE_NOTIFICTION in the fourth parameter indicates that the desktop is a parent window.
10. If there is other service dependence on a service to stop, it will be wrong, so if you need to stop the service is possible by other services, you must use the enumdependentServices () method before stopping. All services that depend on this service will only stop these services. Specific code example, please see MSDN-> Howto-> ID: Q245230.
11. When you start the service, you can use the startup parameters, and the two parameters (DWORD ARGC, LPTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTR *, the second is a parameter array pointer when defining the service_main method. How to pass the parameters, because service_main is not a program entry, the parameter is passed from the command line to the StartService method, and when calling StartService, the second third parameter of StartService is the parameter that is incorporated into service_main. If the service is auto-start, it will start automatically each time it is turned on, and does not handle the opportunity to pass the parameters through the command line. At this time, we only pass the parameters when installing the service. When CreateService, the CreateService's LPBINARYPATHNAME value is set, such as SimpleService.exe Arg1 Arg2, so that whenever the SCM gets the parameter from the main method whenever the SCM starts service, it passes it to the service_main of this service. 12. After starting a service, the Status of Service is "Service_Running" before this time, it is unable to start another service.
Example code:
#include
#include
#include
#include
#include
#include
#include
#define SERVICE_NAME "TSService" #define SERVICE_DISPNAME "vPBX PathFinder TSService" #define SERVICE_DESCRIPTIONNAME "Start vPBX PathFinder service" #define SERVICE_EXENAME "//ServiceFrame.exe"#define LOG_FILENAME" //Service.log"#define START_EXENAME "// vpbxw .exe "#define STOP_EXENAME" //StopServer.exe"#define CMD_EXENAME "-svc" #define REG_ITEM "SOFTWARE // VisionNex // vPBX_Server" #define REG_KEY "home" #define FLAG_FILENAME "//PortKeeper.svc"#define START_DELAY 10000 # define stop_delay 2000 # define count_delay 50 # define time_DELAY 2000
SERVICE_STATUS m_ServiceStatus; SERVICE_STATUS_HANDLE m_ServiceStatusHandle; BOOL bRunning = false; char Path [256]; void WINAPI ServiceMain (DWORD argc, LPTSTR * argv); void WINAPI ServiceCtrlHandler (DWORD Opcode); BOOL InstallService (int flag); BOOL DeleteService (); BOOL StartupService (); BOOL StopService (); BOOL ChangeService (); BOOL EndService (); BOOL QueryReg (); DWORD GetStatus (SC_HANDLE service); void LogService (char * error); BOOL TestTs (int sleep, int count, int sec Bool Waittsstartup (int Sleep, int count, int sec); int main (int Argc, char * argv [=) {if (! QueryReg ()) Return 1; if (argc> 1) {IF (Strcmp (Argv [1], "- i") == 0) {InstallService (0);} else if (strCMP (Argv [1], "- ID") == 0) {InstallService (1);} else f (Argv [1], "- D") == 0) {deleteService ();} else if (strcmp (argv [1], "- r") == 0) {startupService ();} else f (argv [1], "- s") == 0) {stopservice ();} else if (strcmp (argv [1], "- c") == 0) {ChangeService ();} else} (argv [1], "- v") == 0) {PRIN TF ("Server Frame Version: 1.0.0.5: Debug = Pipe (Limit -0.3)");} else {printf ("Unknown Switch USAGE / NFOR Install Use -i, for Uninstall Use -d, for run use -r, for stop use -s / n ");}} else {SERVICE_TABLE_ENTRY DispatchTable [] = {{SERVICE_NAME, ServiceMain}, {NULL, NULL}}; StartServiceCtrlDispatcher (DispatchTable);} return 0;} void WINAPI ServiceMain (DWORD argc, LPTSTR * Argv) {DWORD STATUS; DWORD STATUS; DWORD SPECIFICERROR; LOGSERVICE ("Service Startup ..."); M_ServiceStatus.dwserviceType = service_win32; m_serviceStatus.dwcurrentState = service_start_pending;
m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; m_ServiceStatus.dwWin32ExitCode = 0; m_ServiceStatus.dwServiceSpecificExitCode = 0; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; m_ServiceStatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler); if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE) 0 ) {LogService ( "Error: RegisterServiceCtrlHandler"); return;} / * // create pipe SECURITY_ATTRIBUTES sa; HANDLE hRead, hWrite; sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; / * If (! Cread, & Hwrite, & Sa, 0)) {LogService ("Error On CreatePipe ()");} // --------- hwrite = createfile ("D: // Process. log ", GENERIC_WRITE, FILE_SHARE_READ, & sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); * / PROCESS_INFORMATION pinfo; STARTUPINFO sinfo; ZeroMemory (& sinfo, sizeof (sinfo)); sinfo.cb = sizeof (sinfo); char str Dir [256]; char strDir_stop [256]; strcpy (strDir, Path); strcpy (strDir_stop, Path); strcat (strDir, START_EXENAME); strcat (strDir_stop, STOP_EXENAME); LPCTSTR lpszBinaryPathName = strDir; LPCTSTR lpszBinaryPathName_stop = strDir_stop; LogService ( "Start Create StopServer process"); if (CreateProcess (lpszBinaryPathName_stop, CMD_EXENAME, NULL, NULL, FALSE, 0, NULL, Path, & sinfo, & pinfo)!) {LogService ( "Error: CreateProcess: stop befor start"); return Sleep_Delay); ZeromeMory (& SINFO, SIZEOF (SINFO)); sinfo.cb = sizeof (sinfo); // set process output //sinfo.hstder = hwrite;
//sinfo.hStdOutput = hWrite; sinfo.wShowWindow = SW_SHOW; sinfo.dwFlags = STARTF_USESHOWWINDOW; // | STARTF_USESTDHANDLES; LogService ( "Start Create vPBXW process"); if (CreateProcess (lpszBinaryPathName, CMD_EXENAME, NULL, NULL, TRUE,! 0, NULL, Path, & sinfo, & pinfo)) {LogService ( "Error: CreateProcess: start"); m_ServiceStatus.dwCurrentState = SERVICE_STOPPED; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; m_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; m_ServiceStatus.dwServiceSpecificExitCode = 0; SetServiceStatus (m_ServiceStatusHandle, & m_ServiceStatus); (hWrite)} // CloseHandle;; return LogService ( "Created vPBXW process"); // read pipe / * char buffer [4096] = {0}; DWORD bytesRead = 0; INT i = 1; While (3) {i = I -1; BOOL RET = ReadFile (Hread, Buffer, 4095, & Bytesread, NULL); if (Ret == Null) {LogService ("Read Return Null); BREA K;} if (RET == 0) {LogService ("Read Return 0"); Break;} IF (BytesRead == 0) {LogService ("Read size 0");} else {logservice ("Read Success") Buffer [bytesread] = 0; logservice;}}} // ----- * / if (! Testts (start_delay, count_delay, time_delay) {closehandle (Pinfo.hthread); CloseHandle (Pinfo.hprocess) ; // closeHandle (HREAD); Return;} m_serviceStatus.dwcurrentState = service_running; m_servicestatus.dwcheckpoint = 0;
m_ServiceStatus.dwWaitHint = 0; if (SetServiceStatus (m_ServiceStatusHandle, & m_ServiceStatus)!) {LogService ( "Error: SetServiceStatus: SERVICE_RUNNING"); return;} CloseHandle (pinfo.hThread); CloseHandle (pinfo.hProcess); // CloseHandle (hRead ); return;} BOOL EndService () {PROCESS_INFORMATION pinfo; STARTUPINFO sinfo; ZeroMemory (& sinfo, sizeof (sinfo)); sinfo.cb = sizeof (sinfo); char strDir [256]; strcpy (strDir, Path); strcat ( strDir, STOP_EXENAME); LPCTSTR lpszBinaryPathName = strDir; if (CreateProcess (lpszBinaryPathName, CMD_EXENAME, NULL, NULL, FALSE, 0, NULL, Path, & sinfo, & pinfo!)) {LogService ( "Error: CreateProcess: stop"); return false ;} LogService ( "Service Stop ..."); LogService ( "Service Stop OK"); CloseHandle (pinfo.hThread); CloseHandle (pinfo.hProcess); return true;} void WINAPI ServiceCtrlHandler (DWORD Opcode) {switch ( Opcode) {copy service_control_stop: m_serviceStatus.dwwin32exitcode = 0; M_Services tatus.dwCurrentState = SERVICE_STOPPED; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; SetServiceStatus (m_ServiceStatusHandle, & m_ServiceStatus); bRunning = false; EndService (); break; case SERVICE_CONTROL_SHUTDOWN: bRunning = false; EndService (); char strDir [256 ]; STRCPY (STRDIR, PATH); STRCAT (STRDIR, FLAG_FILENAME); Remove (strdir); Break; Case Service_Control_INTERROGATE: BREAK;} Return;
} BOOL InstallService (int flag) {HANDLE schSCManager, schService; schSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) {printf ( "Error Installing Service / n"); LogService ( "Error: Installing Service : OpenSCManager "); return false;} char strDir [256]; strcpy (strDir, Path); strcat (strDir, SERVICE_EXENAME); LPCTSTR lpszBinaryPathName = strDir; schService = CreateService (schSCManager, SERVICE_NAME, SERVICE_DISPNAME, SERVICE_ALL_ACCESS, // desired access Service_win32_oen_process, // service type service_auto_start, // start type service_error_normal, // error control type lpszbinarypathname, // service's binary null, // noide ordering group NULL, // NO Tag Identifier Null, // No Dependencies Null, // Localsystem Account Null; // No Password IF (SCHSERVICE == Null) {Printf ("Error Installing Service / N"); LogService ("Error: Installing Service: CreateService "); ClosServiceHandle; Return False;} Printf (" Service Installed OK / N "); LogService (" Service Installed OK "); if (Flag ==
1) {ChangeServiceConfig (schService, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);} char description [] = SERVICE_DESCRIPTIONNAME; SERVICE_DESCRIPTION svrDescription; svrDescription.lpDescription = description; ChangeServiceConfig2 (schService , SERVICE_CONFIG_DESCRIPTION, & svrDescription); if) {printf ( "Error Start Service / n"); LogService ( "Error: Start Service: StartService");} (StartService (schService, 0, NULL!) else {printf ( "Service Startup ... / n "); WaitTsStartup (sTART_DELAY, COUNT_DELAY, TIME_DELAY);} CloseServiceHandle (schService); CloseServiceHandle (schSCManager); return true;} BOOL DeleteService () {HANDLE schSCManager; SC_HANDLE hService; SERVICE_STATUS ServStat; schSCManager = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS; IF (SchscManager == Null) {Printf ("Error Uninstalling Service / N"); LogService ("Error: Uninstalling Service: OpenScManager); Return False; } HService = OpenService (schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS); if (hService == NULL) {printf ( "Error Uninstalling Service / n"); LogService ( "Error: Uninstalling Service: OpenService"); CloseServiceHandle (schSCManager); return false ;} if (GetStatus (hService) = SERVICE_STOPPED!) {if (ControlService (hService, SERVICE_CONTROL_STOP, & ServStat)!) {printf ( "Error Stop Service / n"); LogService ( "Error: Stop Service: ControlService"); CloseServiceHandle (HService); ClosESERVICEHANDE (SCHSCMANAGER); Return False;} Printf ("Service Stop ... / N"); logservice
Service stop ... "; Sleep_Delay); Printf (" Service Stop OK / N "); LogService (" Service Stop OK ");} if (! DeleteService (HService)) {Printf (" Error Uninstalling Service / n "); LogService (" Error: Uninstalling Service: DeleteService "); CloseServiceHandle (hService); CloseServiceHandle (schSCManager); return false;} CloseServiceHandle (hService); CloseServiceHandle (schSCManager); printf (" Service Uninstalled OK / n ") ; LogService ( "Service Uninstalled OK"); return true;} BOOL ChangeService () {HANDLE schSCManager; SC_HANDLE hService; schSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) {printf ( "Error Change Service / n "); LogService (" Error: Change Service: OpenSCManager "); return false;} hService = OpenService (schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS); if (hService == NULL) {printf (" Error Change Service / n ") LogService ("Error: Change Service: OpenService); ClosESERVICEHANDE (SCHSCMANAGER); Return False;} DWORD dwSize; LPQUERY_SERVICE_CONFIG lpConfig; lpConfig = (LPQUERY_SERVICE_CONFIG) LocalAlloc (LPTR, 1024); if (QueryServiceConfig (hService, lpConfig, 1024, & dwSize)!) {CloseServiceHandle (hService); printf ( "! Query service config failed / n") ; LogService; return false; ( "Query service config failed!")} if (lpConfig-> dwServiceType == SERVICE_WIN32_OWN_PROCESS) {ChangeServiceConfig (hService, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL , NULL); Printf ("Service CAN Interact with Desk / N);
LogService ( "Service can interact with desktop");} if (lpConfig-> dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) {ChangeServiceConfig (hService, SERVICE_WIN32_OWN_PROCESS, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); printf ( "Service can not interact with desktop / n"); LogService ( "Service can not interact with desktop");} CloseServiceHandle (hService); CloseServiceHandle (schSCManager); return true;} BOOL StartupService () { HANDLE schSCManager; SC_HANDLE hService; SERVICE_STATUS ServStat; schSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) {printf ( "Error Start Service / n"); LogService ( "Error: Start Service: OpenSCManager") ; return false;} hService = OpenService (schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS); if (hService == NULL) {printf ( "Error Start Service / n"); LogService ( "Error: Start Service: OpenService"); CloseServiceHandle (schSCManager Return False;} i f (! GetStatus (hService) = SERVICE_STOPPED) {printf ( "Service already startup / n"); LogService ( "Error: Service already startup"); CloseServiceHandle (hService); CloseServiceHandle (schSCManager); return false;} if (! StartService (HService, 0, Null) {Printf ("Error Start Service / N"); LogService ("Error: Start Service: StartService);} else {printf (" Service Startup ... / n "); waittsstartup (Start_delay, count_delay, time_delay);} closESERVICEHANDE (HSERVICE); ClosESERVICEHANDE (SCHSCMANAGER); Return True;} Bool STOPService () {Handle Schscmanager; sc_handle hservice;
SERVICE_STATUS ServStat; schSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) {printf ( "Error stop Service / n"); LogService ( "Error: stop Service: OpenSCManager"); return false;} hService = OpenService (schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS); if (hService == NULL) {printf ( "Error stop Service / n"); LogService ( "Error: stop Service: OpenService"); CloseServiceHandle (schSCManager); return false;} if (! GetStatus (hService) = SERVICE_STOPPED) {if (ControlService (hService, SERVICE_CONTROL_STOP, & ServStat)!) {printf ( "Error Stop Service / n"); LogService ( "Error: Stop Service: ControlService");} else { Printf ("Service Stop ... / N"); SLEEP (STOP_DELAY); Printf ("Service Stop OK / N");}} else {printf ("Service Already Stop / N"); LogService ("Error: Service Already Stop ");} ClosServiceHandle (HService); ClosESERVICEHANDE (SCHSCMANAGER); Return True;} DWORD GETSTATUS (SC_HANDLE Service) {Bool SUC CESS; SERVICE_STATUS status; DWORD CurrentState; SUCCESS = QueryServiceStatus (service, & status); switch (status.dwCurrentState) {case SERVICE_RUNNING: CurrentState = SERVICE_RUNNING; break; case SERVICE_STOPPED: CurrentState = SERVICE_STOPPED; break; case SERVICE_PAUSED: CurrentState = SERVICE_PAUSED; break ; case SERVICE_CONTINUE_PENDING: CurrentState = SERVICE_CONTINUE_PENDING; break; case SERVICE_PAUSE_PENDING: CurrentState = SERVICE_PAUSE_PENDING; break; case SERVICE_START_PENDING: CurrentState = SERVICE_START_PENDING; break;
case SERVICE_STOP_PENDING: CurrentState = SERVICE_STOP_PENDING; break; default: break;} return CurrentState;} void LogService (char * error) {FILE * fp = NULL; char strDir [256]; strcpy (strDir, Path); strcat (strDir, LOG_FILENAME ); Lpctstr lpszbinarypathname = strdir; char * filename = strdir; time_t currenttime = time (null); char * ctime = ctime (¤ttime); fp = fopen (filename, "a"); fPrintf (fp, "% s% S / N / N ", ctime, error); fflush (fp); fclose (fp);} Bool queryReg () {BOOL RET = true; hkey hkey; dword dwtype = reg_sz; dword dwlength = 256; struct hkey __ * rootkey ; TCHAR * SubKey; TCHAR * KeyName; TCHAR * ValueName; RootKey = HKEY_LOCAL_MACHINE; SubKey = REG_ITEM; ValueName = REG_KEY; if (RegOpenKeyEx (RootKey, SubKey, 0, KEY_READ, & hKey) == ERROR_SUCCESS) {if (RegQueryValueEx (hKey, ValueName, NULL, & dwType, (unsigned char *) Path, & dwLength) = ERROR_SUCCESS) {printf ( "Registry Query Error / n"); LogService ( "Error: QueryReg: RegQueryValueEx"); ret = false;}! RegCloseK Else {Printf ("Registry Query Error / N"); LogService ("Error: OpenReg: RegopenKeyex"); RET = false;} return return;} Bool Testts (int Sleep, int COUNT, INT SEC ) {FILE * fp = NULL; char strDir [256]; strcpy (strDir, Path); strcat (strDir, FLAG_FILENAME); LPCTSTR lpszBinaryPathName = strDir; char * fileName = strDir; int i = count; Sleep (sleep); while (i) {SLEEP (SEC); fp = fopen (filename, "r"); if (fp! = null) {brunning = true; logservice ("TS Startup OK"); LogService ("Service Startup OK"); Fclose (fp); return true;
} I = i - 1;} MessageBox (NULL, ". Port 8080 may be in use by another application or service", "TS Startup failure", MB_DEFAULT_DESKTOP_ONLY); LogService ( "Error: TS Startup failure"); m_ServiceStatus.dwCurrentState = SERVICE_STOPPED; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; //m_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; //m_ServiceStatus.dwServiceSpecificExitCode = 1; m_ServiceStatus.dwWin32ExitCode = 0; m_ServiceStatus.dwServiceSpecificExitCode = 0; SetServiceStatus (m_ServiceStatusHandle, & m_ServiceStatus); return false;} BOOL WaitTsStartup (int sleep, int count, int sec) {FILE * fp = NULL; char strDir [256]; strcpy (strDir, Path); strcat (strDir, FLAG_FILENAME); LPCTSTR lpszBinaryPathName = strDir; char * Filename = strdir; int i = count; Sleep (Sleep); while (i) {SLEEP (SEC); fp = fopen (filename, "r"); if (fp! = null) {Printf ("Service Startup OK / n "); fclose (fp); Return True;} = i - 1;} Printf ("Error: Service Startup Failure: TS Startup Failure / N"); Return False;} Sample Code: This example is MSDN, which is used to stop one other service dependence Service.
/ * Copyright (c) 1998 Microsoft Corporation Module Name: threadbased.c Description:. This sample illustrates how to manage threads in a Windows NT System Service To install or remove the service, build the executable as a Win32 Console Application and use . the SC utility in the Windows NT Resource Kit See the Simple Service Sample in the Win32 SDK for sample code to install and remove a service The following import libraries are required:. advapi32.lib user32.lib Dave McPherson (davemm) 11-March -98 - * / # include # include
#include
// // Global variables // HANDLE hStopEvent;. HANDLE hThreads [3] = {NULL, NULL, NULL}; LPTSTR lpszServiceName; SERVICE_STATUS_HANDLE ssh; // // Function prototypes // DWORD WINAPI ThreadProc (LPVOID lpParameter);. Void WINAPI Service_Main (DWORD dwArgc, LPTSTR * lpszArgv); void WINAPI Service_Ctrl (DWORD dwCtrlCode); void ErrorStopService (LPTSTR lpszAPI); void SetTheServiceStatus (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint); // // _tmain - Entry point for service. Calls StartServiceCtrlDispatcher // and then blocks until the ServiceMain function returns. // void _tmain (int argc, TCHAR * argv []) {SERVICE_TABLE_ENTRY ste [] = {{TEXT ( ""), (LPSERVICE_MAIN_FUNCTION) Service_Main}, {Null, null}}; outputdebugstring (Text ("Entered Service Code / N")); if (! StartServiceCtrldispatcher (ste)) {tchar error [256]; WSPrintf (Error, TEXT ( ". Error code for StartServiceCtrlDispatcher:% u / n"), GetLastError ()); OutputDebugString (error);} else OutputDebugString (TEXT ( "! StartServiceCtrlDispatcher returned / n"));} // // Service_Main - This is called by the service control manager after // the call to StartServiceCtrlDispatcher // void WINAPI Service_Main (DWORD dwArgc, LPTSTR * lpszArgv) {DWORD ThreadId;. DWORD t; DWORD dwWaitRes;. // Obtain the name of the service lpszServiceName = lpszArgv [0]; // register the service ctrl handler. Ssh =
RegisterServiceCtrlHandler (lpszServiceName, (LPHANDLER_FUNCTION) Service_Ctrl); // Create the event to signal the service to stop hStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);. If (hStopEvent == NULL) ErrorStopService (TEXT ( "CreateEvent") ); / ******************************************************** ***************************** / // this is where you can put one-time WORK THAT You want to completion // before starting. For (t = 0; t <3; t ) {hthreads [t] = CreateThread (NULL, 0, ThreadProc, (LPVOID) T, 0, & ThreadID; if (Hthreads [T] == Invalid_Hthreads [THREAD) ERRORSTOPSERVICE (Text ("CreateThread");} / ************************************************** ****************** / // the service has started. SetTheServiceStatus (Service_Running, 0, 0, 0); OutputDebugstring (Text ("SettheServiceStatus, Service_Running / N"))) ; // // main loop for t He Service. <----------------------------- // while (WaitforsingleObject (hstopevent, 1000)! = Wait_Object_0) {/ * *********************************************************** *********** / // main loop for service. / *************************************** ******************************************** /} // now Wait for Threads to EXIT. FOR (T = 1 True; T ) {IF (DWWAITRES = WaitFormultipleObjects (3, hthreads, true, 1000) == Wait_Object_0) Break; Else IF ((dwweitres == Wait_failed) || (dwwaitres ==
WAIT_ABANDONED)) ErrorStopService (TEXT ( "WaitForMultipleObjects")); else SetTheServiceStatus (SERVICE_STOP_PENDING, 0, t, 3000);!} // close the event handle and the thread handle if (CloseHandle (hStopEvent)) ErrorStopService (TEXT ( "CloseHandle ")); If (! CLOSEHANDLE)) ErrorstopService (Text (" CloseHandle ")); if (! CloseHandle (HTHREADS [1])) ErrorstopService (Text (" CloseHandle "); if (!! (hThreads [2])) ErrorStopService (TEXT ( "CloseHandle")); // Stop the service OutputDebugString (TEXT ( "SetTheServiceStatus, SERVICE_STOPPED / n"));. SetTheServiceStatus (SERVICE_STOPPED, NO_ERROR, 0, 0);} / / // Service_Ctrl - Where control signals from the Service Control Mgr // are handled // void WINAPI Service_Ctrl (DWORD dwCtrlCode) {DWORD dwState = SERVICE_RUNNING; switch (dwCtrlCode) {case SERVICE_CONTROL_STOP: dwStat. e = SERVICE_STOP_PENDING; break; case SERVICE_CONTROL_SHUTDOWN: dwState = SERVICE_STOP_PENDING; break; case SERVICE_CONTROL_INTERROGATE: break; default: break;} // Set the status of the service SetTheServiceStatus (dwState, NO_ERROR, 0, 0); OutputDebugString (TEXT ( ". SetTheServiceStatus, Service_ctrl function / n ")); // Tell Service_main thread to stop. If ((dwctrlcode == service_control_stop) || (dwctrlcode ==
SERVICE_CONTROL_SHUTDOWN)) {if (SetEvent (hStopEvent)) ErrorStopService (TEXT ( "SetEvent")); else OutputDebugString (TEXT ( "Signal service_main thread / n"));!}} // // ThreadProc - Thread procedure for all three worker threads // DWORD WINAPI ThreadProc (LPVOID lpParameter) {INT nThreadNum = (INT) lpParameter;. TCHAR szOutput [25]; while (! WaitForSingleObject (hStopEvent, 1000) = WAIT_OBJECT_0) {// Just to have something to do, it Will Beep Every Second. Sleep (1000); WSPrintf (Szoutput, Text ("/ nthread% D Says Beep / N"), NTHREADNUM); OutputDebugString (Szoutput); // Send Visual To Debugger.} Return 0;} // . // SetTheServiceStatus - This just wraps up SetServiceStatus // void SetTheServiceStatus (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint) {SERVICE_STATUS ss; // Current status of the s . Ervice // // Disable control requests until the service is started // if (dwCurrentState == SERVICE_START_PENDING) ss.dwControlsAccepted = 0;. Else ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; // Other flags include SERVICE_ACCEPT_PAUSE_CONTINUE // and SERVICE_ACCEPT_SHUTDOWN. // Initialize ss structure. S.dwserviceType = service_win32_oen_process; ss.dwserviceSpecificeXitcode = 0; ss.dwcurrentState = dwcurrentState; ss.dwwin32exitcode = dwwin32exitcode;
ss.dwCheckPoint = dwCheckPoint; ss.dwWaitHint = dwWaitHint; // Send status of the service to the Service Controller if ErrorStopService (TEXT ( "SetServiceStatus")). (SetServiceStatus (ssh, & ss)!);} // // ErrorStopService - Use this when there is an API error or bad // situation this just ends the service and // displays an error message to the debugger // void ErrorStopService (LPTSTR lpszAPI) {INT t; TCHAR buffer [256] = TEXT (. ""); Tchar error [1024] = text (""); lpvoid lpvMessageBuffer; dword dwaitres; wsprintf (buffer, text ("API =% s,"), lpszapi; lstrcat (error, buffer); ZeromeMory , sizeof (buffer)); wsprintf (buffer, TEXT ( "error code =% d,"), GetLastError ()); lstrcat (error, buffer);. // Obtain the error string FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & lpvMessageBuffer, 0, NULL); ZeroMemory ((LPVOID) buffer, (DWORD) sizeof (buffer)); wsprintf (buffer, TEXT ( "message =% s "), (TCHAR *) lpvMessageBuffer); lstrcat (error, buffer); // Free the buffer allocated by the system LocalFree (lpvMessageBuffer);. // Write the error string to the debugger OutputDebugString (error);. // If YOU HAVETEADS RUNNING, TELL THEADS RUNNING, SOMETHING WENT // WRONG, AND You NEED To Stop The So You CAN Inform The SCM. setEvent (hstopevent);