前面我们所讲的“服务程序”,更准确地说是服务控制程序,例如我们通过输入应用的路径,将一个应用程序添加到服务控制管理器。一个服务控制程序可以将一个程序添加到服务控制管理器中,并控制它的运行、停止和删除等。那么怎么避免手动添加的方式,直接将我们想要运行的代码添加到服务中呢?这需要我们建立一个完整的服务程序,要同时包括服务主程序和服务控制程序。
关于服务主程序
服务主程序包括一个main函数作为程序的标准入口,一个ServiceMain函数作为服务程序的入口,一个Handler函数实现服务启动,停止等功能,最后是一个MyWork函数,这里面可以写入我们想要运行的代码,也就是服务要实现的功能。
我们来看一个程序,该程序实现的功能是在服务运行期间,循环执行MessageBox函数;可以在cmd上运行应用程序,给其传递参数,实现对于服务的控制。这个程序在逻辑的实现上比较简单,某些函数可以直接查看msdn文档,附上链接地址https://technet.microsoft.com/zh-cn/library/
#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#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有日志文件