前面我們所講的“服務程序”,更准確地說是服務控制程序,例如我們通過輸入應用的路徑,將一個應用程序添加到服務控制管理器。一個服務控制程序可以將一個程序添加到服務控制管理器中,並控制它的運行、停止和刪除等。那麼怎麼避免手動添加的方式,直接將我們想要運行的代碼添加到服務中呢?這需要我們建立一個完整的服務程序,要同時包括服務主程序和服務控制程序。
關於服務主程序
服務主程序包括一個main函數作為程序的標准入口,一個ServiceMain函數作為服務程序的入口,一個Handler函數實現服務啟動,停止等功能,最後是一個MyWork函數,這裡面可以寫入我們想要運行的代碼,也就是服務要實現的功能。
我們來看一個程序,該程序實現的功能是在服務運行期間,循環執行MessageBox函數;可以在cmd上運行應用程序,給其傳遞參數,實現對於服務的控制。這個程序在邏輯的實現上比較簡單,某些函數可以直接查看msdn文檔,附上鏈接地址https://technet.microsoft.com/zh-cn/library/
#define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winsvc.h> #include <stdio.h> #define SLEEP_TIME 5000 #define LOG_FILE "c:\\MemoryWatch.txt" #define SERVICE_NAME "servitest" #define SERVICE_DESC "test" #define SERVICE_DISPLAY_NAME "test" SERVICE_STATUS ServiceStatus; SERVICE_STATUS_HANDLE hStatus; SC_HANDLE scm; SC_HANDLE scv; void ServiceMain(int argc, char** argv); void ControlHandler(DWORD request); void Log(char* filename); int startFunc(); void OnStart(); void OnCreate(); void OnDelete(); void OnStop(); int main(int argc, char* argv[]) { // Service Name:MemoryStatus // Service Handle Function: ServiceMain() SERVICE_TABLE_ENTRY ServiceTable[2] = { { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL,NULL} }; if(argc == 2) { if(!stricmp(argv[1],"-create")) { OnCreate(); return 0; } else if(!stricmp(argv[1],"-delete")) { OnDelete(); return 0; } else if(!stricmp(argv[1],"-start")) { OnStart(); return 0; } else if(!stricmp(argv[1],"-stop")) { OnStop(); return 0; } else { printf("invailid parameter\n"); return 0; } } StartServiceCtrlDispatcher(ServiceTable); return 0; } void Log(char* str) { FILE* fp = fopen(LOG_FILE, "a+"); if(fp == NULL) { printf("error to open file: %d\n", GetLastError()); return; } fprintf(fp, "%s\n", str); fflush(fp); fclose(fp); } void ServiceMain(int argc, char** argv) { BOOL bRet; int result; bRet = TRUE; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwServiceType = SERVICE_WIN32; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; ServiceStatus.dwServiceSpecificExitCode = 0; hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)ControlHandler); if(hStatus == (SERVICE_STATUS_HANDLE)0) { // log failed return; } //service status update ServiceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(hStatus, &ServiceStatus); while(ServiceStatus.dwCurrentState == SERVICE_RUNNING) { result = startFunc(); if(result) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwWin32ExitCode = -1; SetServiceStatus(hStatus, &ServiceStatus); return; } } } int startFunc() { MessageBox(NULL, "startFunc", SERVICE_NAME, MB_OK); return 0; } void ControlHandler(DWORD request) { switch(request) { case SERVICE_CONTROL_STOP: Log("Monitoring stopped."); ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (hStatus, &ServiceStatus); return; case SERVICE_CONTROL_SHUTDOWN: Log("Monitoring stopped."); ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus (hStatus, &ServiceStatus); return; default: break; } SetServiceStatus (hStatus, &ServiceStatus); } void OnCreate() { char filename[MAX_PATH]; DWORD dwErrorCode; GetModuleFileName(NULL, filename, MAX_PATH); printf("Creating Service .... "); scm = OpenSCManager(0/*localhost*/, NULL/*SERVICES_ACTIVE_DATABASE*/, SC_MANAGER_ALL_ACCESS/*ACCESS*/); if (scm == NULL) { printf("OpenSCManager error:%d\n", GetLastError()); return; } scv = CreateService(scm,//句柄 SERVICE_NAME,//服務開始名 SERVICE_DISPLAY_NAME,//顯示服務名 SERVICE_ALL_ACCESS, //服務訪問類型 SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,//服務類型 SERVICE_AUTO_START, //自動啟動服務 SERVICE_ERROR_IGNORE,//忽略錯誤 filename,//啟動的文件名 NULL,//name of load ordering group (載入組名) NULL,//標簽標識符 NULL,//相關性數組名 NULL,//帳戶(當前) NULL); //密碼(當前) if (scv == NULL) { dwErrorCode = GetLastError(); if(dwErrorCode!=ERROR_SERVICE_EXISTS) { printf("Failure !\n"); CloseServiceHandle(scm); return ; } else { printf("already Exists !\n"); } } else { printf("Success !\n"); CloseServiceHandle(scv); } CloseServiceHandle(scm); scm = scv = NULL; } void OnDelete() { scm=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if (scm!=NULL) { scv=OpenService(scm,SERVICE_NAME,SERVICE_ALL_ACCESS); if (scv != NULL) { QueryServiceStatus(scv,&ServiceStatus); if (ServiceStatus.dwCurrentState==SERVICE_RUNNING) { ControlService(scv,SERVICE_CONTROL_STOP,&ServiceStatus); } DeleteService(scv); CloseServiceHandle(scv); } CloseServiceHandle(scm); } scm = scv = NULL; } void OnStart() { DWORD dwErrorCode; //Starting Service printf("Starting Service .... "); scm = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if(scm != NULL) { scv = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS); if (scv != NULL) { if(StartService(scv, 0, NULL)==0) { dwErrorCode = GetLastError(); if(dwErrorCode == ERROR_SERVICE_ALREADY_RUNNING) { printf("already Running !\n"); CloseServiceHandle(scv); CloseServiceHandle(scm); return ; } } else { printf("Pending ... "); } //wait until the servics started while(QueryServiceStatus(scv,&ServiceStatus)!=0) { if(ServiceStatus.dwCurrentState == SERVICE_START_PENDING) { Sleep(100); } else { break; } } CloseServiceHandle(scv); } else { //error to OpenService printf("error to OpenService\n"); } CloseServiceHandle(scm); } else { //fail to OpenSCManager } /* if(InstallServiceStatus.dwCurrentState != SERVICE_RUNNING) { printf("Failure !\n"); } else { printf("Success !\nDumping Description to Registry...\n"); RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NtBoot", 0, KEY_ALL_ACCESS, &hkResult); RegSetValueEx(hkResult, "Description", 0, REG_SZ, (unsigned char *)"Driver Booting Service", 23); RegCloseKey(hkResult); } CloseServiceHandle(schSCManager); CloseServiceHandle(schService); }// */ scm = scv = NULL; } void OnStop() { scm = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if(scm != NULL) { scv = OpenService(scm,SERVICE_NAME,SERVICE_STOP | SERVICE_QUERY_STATUS); if (scv!=NULL) { QueryServiceStatus(scv,&ServiceStatus); if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) { ControlService(scv,SERVICE_CONTROL_STOP,&ServiceStatus); } CloseServiceHandle(scv); } CloseServiceHandle(scm); } scm = scv = NULL; }
程序編譯好之後,運行cmd。我編譯好的程序的完整路徑是 C:\hi\Debug\hi.exe
執行 C:\hi\Debug\hi.exe -create創建服務
執行C:\hi\Debug\hi.exe -start 啟動服務
……
在c盤MemoryWatch.txt有日志文件