昨天一同学入职考核,需要用C/C++写一个服务程序,从XML读取配置,定期运行指定程序/脚本/命令……
同学无解。。向我求助,然后我也没写过windows服务程序,于是琢磨了一下,弄出一个很简单的DEMO。
先从网上掏了一个VC6的程序叫 memorystatus ,其功能主要为启动一个服务定期向文件内写入当前剩余内存。
然后看了一下windows自带一个sc.exe 用于管理服务。
再掏了个轻量级的XML解析器“Markup”,貌似是基于MFC的,没仔细看。。直接include用。
于是基于这三个玩意改改。。 就成这样了……
#include "Markup.h"
#include <stdio.h>
#include <string>
using namespace std;
#define SLEEP_TIME 5000 //间隔时间
#define LOGFILE "C:\\test\\log.txt" //日志文件路径
#define XMLFILE "C:\\test\\test.xml" //xml文件路径
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();
int WriteToLog(const char* str);
//读XML文件
string LoadXMLFile()
{
//具体如果需要修改的话,到网上搜CMarkup类的用法
string filepath;
CMarkup xml;
xml.Load(XMLFILE);
if(xml.FindElem("PATH"))
{
filepath = xml.GetData();
}
WriteToLog(filepath.c_str());
return filepath;
}
//写日志文件
int WriteToLog(const char* str)
{
FILE* log;
log = fopen(LOGFILE, "a+");
if (log == NULL){
return -1;
}
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
//执行应用程序
void Run()
{
string filepath = LoadXMLFile();
WinExec(filepath.c_str(),SW_HIDE);
}
int InitService()
{
int result;
result = WriteToLog("Monitoring started.");
return(result);
}
// Control Handler
void ControlHandler(DWORD request)
{
switch(request)
{
case SERVICE_CONTROL_STOP:
WriteToLog("Monitoring stopped.");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;
case SERVICE_CONTROL_SHUTDOWN:
WriteToLog("Monitoring stopped.");
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;
default:
break;
}
// Report current status
SetServiceStatus (hStatus, &ServiceStatus);
return;
}
void ServiceMain(int argc, char** argv)
{
int error;
ServiceStatus.dwServiceType =
SERVICE_WIN32;
ServiceStatus.dwCurrentState =
SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted =
SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(
"MemoryStatus",
(LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
// Registering Control Handler failed
return;
}
// Initialize Service
error = InitService();
if (error)
{
// Initialization failed
ServiceStatus.dwCurrentState =
SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
// We report the running status to SCM.
ServiceStatus.dwCurrentState =
SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);
// The worker loop of a service
while (ServiceStatus.dwCurrentState ==
SERVICE_RUNNING)
{
Run();//执行应用程序
Sleep(SLEEP_TIME);
}
return;
}
void main(int argc, char* argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// Start the control dispatcher thread for our service
StartServiceCtrlDispatcher(ServiceTable);
}
test.xml这么写:
<PATH>C:\test\test.bat</PATH>
这里都是用的绝对定位,服务程序默认工作目录 windows/system32,然后看了一下。。没找到C/C++怎么找服务程序的启动目录。。只找到C#的方法。。懒得管他了。