前面我們所講的“服務程序”,更准確地說是服務控制程序,例如我們通過輸入應用的路徑,將一個應用程序添加到服務控制管理器。一個服務控制程序可以將一個程序添加到服務控制管理器中,並控制它的運行、停止和刪除等。那麼怎麼避免手動添加的方式,直接將我們想要運行的代碼添加到服務中呢?這需要我們建立一個完整的服務程序,要同時包括服務主程序和服務控制程序。
關於服務主程序
服務主程序包括一個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有日志文件