我得先总结一下步骤:
一、在main函数中的操作
1.先创建一个main主函数,在main主函数中创建创建一个服务程序入口函数列的结构体并将其初始化
机构体SERVICE_TABLE_ENTRY DispatchTable[2];
假设定义的服务入口函数是(LPSERVICE_MAIN_FUNCTION)ServiceMain0
2.由服务程序入口函数表启动一个新服务程序线程
SERVICE_TABLE_ENTRY DispatchTable[2]
二、在(LPSERVICE_MAIN_FUNCTION)ServiceMain0函数中的操作
3.在服务程序入口主函数中,创建一个服务状态的结构体,并将其初始化SERVICE_STATUS
SERVICE_STATUS m_ServiceStatus;
4.注册服务状态控制函数
SERVICE_STATUS_HANDLE m_ServiceStatusHandle = RegisterServiceCtrlHandler(“zcm_service0”,(LPHANDLER_FUNCTION)ServiceCtrlHandler0);
注册服务状态控制函数后,会返回一个操作状态服务函数的句柄,注册成功之后,其实服务就已经开始运行了
5.修改服务程序的工作状态,并将修改后的状态报告SCM管理程序
//修改服务状态
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
//报告运行状态到mc
SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);
6.状态报告给SCM管理程序后,我们的服务就可以正常进行了,用一个while(bRunning)循环,不断处理各种情况,提供服务
三、服务状态管理程序(LPHANDLER_FUNCTION)ServiceCtrlHandler0) 函数中的操作
对服务程序的启动、停止、暂停、恢复功能进行操作
根据传递的参数,用switch(dwControl )对各种状态情况进行处理
1.当收到不同的状态时,将采取一定的操作,控制第二步(LPSERVICE_MAIN_FUNCTION)ServiceMain0函数中的操作
switch(Opcode)
{
case SERVICE_CONTROL_STOP:
bRunning = FALSE;
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_SHUTDOWN:
bRunning = FALSE;
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
2.ServiceMain0函数响应状态后,并执行了相关的操作,那么,再次报告工作状态给scm管理程序
对服务管理程序中的三个函数的分工和之前的联系进行说明,这也正是软件设计步骤,后面就是详细的参数和函数的具体使用
服务程序编好之后,不能双击执行,有三种方法进行操作
1.使用Services.msc程序进行可视化的编辑,操纵服务工作状态,缺点是不能添加我们写的程序到服务列表中
2.使用mc.exe程序进行控制zcm为我创建的服务名
mc.exe create zcm binpath= c:\zcm_service.exe //创建服务
mc.exe query zcm //查询服务状态
mc.exe start zcm //启动服务
mc.exe stop zcm //停止服务
mc.exe delete zcm //卸载服务
3.编写代码来控制SCM,自动化的处理方法,推荐
1.SERVICE_STATUS 是服务状态结构,用于标记服务的状态
typedef struct _SERVICE_STATUS {DWORD dwServiceType; //服务可执行文件的类型DWORD dwCurrentState;DWORD dwControlsAccepted;DWORD dwWin32ExitCode;DWORD dwServiceSpecificExitCode;DWORD dwCheckPoint;DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;
dwServiceType 的取值说明:
// Service Types (Bit Mask)
#define SERVICE_WIN32_OWN_PROCESS 0x00000010 //可执行文件中只有一个单独的服务
#define SERVICE_WIN32_SHARE_PROCESS 0x00000020 //拥有多个服务
#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | \SERVICE_WIN32_SHARE_PROCESS) // win32程序服务
#define SERVICE_INTERACTIVE_PROCESS 0x00000100 //服务需要和桌面发生交互#define SERVICE_KERNEL_DRIVER 0x00000001 //核心服务
#define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 //文件系统服务
#define SERVICE_ADAPTER 0x00000004 //适配器服务
#define SERVICE_RECOGNIZER_DRIVER 0x00000008#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | \SERVICE_FILE_SYSTEM_DRIVER | \SERVICE_RECOGNIZER_DRIVER)#define SERVICE_INTERACTIVE_PROCESS 0x00000100#define SERVICE_TYPE_ALL (SERVICE_WIN32 | \SERVICE_ADAPTER | \SERVICE_DRIVER | \SERVICE_INTERACTIVE_PROCESS)
dwCurrentState 用于通知SCManger
// Service State -- for CurrentState
//
#define SERVICE_STOPPED 0x00000001 //服务停止
#define SERVICE_START_PENDING 0x00000002 //初始态,用于初始化,将要开始运行服务
#define SERVICE_STOP_PENDING 0x00000003 //将要停止服务
#define SERVICE_RUNNING 0x00000004 //服务正在运行
#define SERVICE_CONTINUE_PENDING 0x00000005 //将要暂停后继续
#define SERVICE_PAUSE_PENDING 0x00000006 //将要暂停
#define SERVICE_PAUSED 0x00000007 //服务已暂停
dwControlsAccepted 服务接受什么样的控制通知
// Controls Accepted (Bit Mask)
//
#define SERVICE_ACCEPT_STOP 0x00000001 //该服务可以被停止
#define SERVICE_ACCEPT_PAUSE_CONTINUE 0x00000002 //该服务可以被暂停和继续
#define SERVICE_ACCEPT_SHUTDOWN 0x00000004 //当系统关闭时通知该服务
#define SERVICE_ACCEPT_PARAMCHANGE 0x00000008 //该服务可以在不停止和重启的情况下重新读取其启动参数
#define SERVICE_ACCEPT_NETBINDCHANGE 0x00000010 //该服务是一个网络成分,可在不停止和重启的情况下接受绑定的变化
#define SERVICE_ACCEPT_HARDWAREPROFILECHANGE 0x00000020
#define SERVICE_ACCEPT_POWEREVENT 0x00000040
#define SERVICE_ACCEPT_SESSIONCHANGE 0x00000080
#define SERVICE_ACCEPT_PRESHUTDOWN 0x00000100 //该服务可执行预关闭任务
#define SERVICE_ACCEPT_TIMECHANGE 0x00000200
#define SERVICE_ACCEPT_TRIGGEREVENT 0x00000400
dwWin32ExitCode:错误码,用于在服务启动或关闭时报错;默认设置为0
dwServiceSpecificExitCode:特定于服务的错误码,用于在服务启动或关闭时报错;默认设置为0
dwCheckPoint:检测点值,服务周期性的增加该值,以报告服务在一段长期时间内所做的启动,停止,暂停,继续的处理;默认设置为0
dwWaitHint:以毫秒为单位的估计时间,用于估计启动、停止、暂停、继续操作的时间;默认设置为0,只有当服务启动超过三十秒时,才进行设置
SERVICE_STATUS_HANDLE 服务状态句柄
RegisterServiceCtrlHandler注册服务状态控制函数,将LPHANDLER_FUNCTION的服务状态函数注册到zcm_service0的服务中去,然后返回一个可操作的服务状态句柄
SERVICE_STATUS_HANDLE m_ServiceStatusHandle = RegisterServiceCtrlHandler("zcm_service0",(LPHANDLER_FUNCTION)ServiceCtrlHandler0);
注册成功服务状态函数后,就可以修改服务的状态信息,将服务由初始化的SERVICE_START_PENDING修改为SERVICE_RUNNING状态
//修改服务状态
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
//报告运行状态到mc
SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);
SERVIcE_STATUS结构体的状态修改后,要将修改后的状态信息设置到scManger管理程序中
RegisterServiceCtrlHandler 注册服务函数
__checkReturn
WINADVAPI
SERVICE_STATUS_HANDLE
WINAPI
RegisterServiceCtrlHandlerA(__in LPCSTR lpServiceName, //服务名称__in __callbackLPHANDLER_FUNCTION lpHandlerProc //服务状态控制函数);
__checkReturn
WINADVAPI
SERVICE_STATUS_HANDLE
WINAPI
RegisterServiceCtrlHandlerW(__in LPCWSTR lpServiceName,__in __callbackLPHANDLER_FUNCTION lpHandlerProc);
#ifdef UNICODE
#define RegisterServiceCtrlHandler RegisterServiceCtrlHandlerW
#else
#define RegisterServiceCtrlHandler RegisterServiceCtrlHandlerA
#endif // !UNICODE
SetServiceStatus 服务状态设置函数,修改服务状态后,要将服务状态设置到scm管理器中
WINADVAPI
BOOL
WINAPI
SetServiceStatus(__in SERVICE_STATUS_HANDLE hServiceStatus, //服务状态操作句柄__in LPSERVICE_STATUS lpServiceStatus //SERVICE_STATUS状态结构体指针);
LPHANDLER_FUNCTION服务状态控制函数,还有一个Ex的版本
//
// Prototype for the Service Control Handler Function
//typedef VOID (WINAPI *LPHANDLER_FUNCTION)(DWORD dwControl //状态参数);typedef DWORD (WINAPI *LPHANDLER_FUNCTION_EX)(DWORD dwControl, //状态参数DWORD dwEventType,LPVOID lpEventData,LPVOID lpContext);
dwControl状态控制
/ Controls
//
#define SERVICE_CONTROL_STOP 0x00000001 //停止
#define SERVICE_CONTROL_PAUSE 0x00000002 //暂停
#define SERVICE_CONTROL_CONTINUE 0x00000003 //继续
#define SERVICE_CONTROL_INTERROGATE 0x00000004 //查询
#define SERVICE_CONTROL_SHUTDOWN 0x00000005 //关机时
#define SERVICE_CONTROL_PARAMCHANGE 0x00000006 //参数变化进
#define SERVICE_CONTROL_NETBINDADD 0x00000007 //网络绑定时
#define SERVICE_CONTROL_NETBINDREMOVE 0x00000008
#define SERVICE_CONTROL_NETBINDENABLE 0x00000009
#define SERVICE_CONTROL_NETBINDDISABLE 0x0000000A
#define SERVICE_CONTROL_DEVICEEVENT 0x0000000B
#define SERVICE_CONTROL_HARDWAREPROFILECHANGE 0x0000000C
#define SERVICE_CONTROL_POWEREVENT 0x0000000D
#define SERVICE_CONTROL_SESSIONCHANGE 0x0000000E
#define SERVICE_CONTROL_PRESHUTDOWN 0x0000000F
#define SERVICE_CONTROL_TIMECHANGE 0x00000010
#define SERVICE_CONTROL_TRIGGEREVENT 0x00000020
Service服务入口表,如果是一个程序入口程,则将结构体设置成2个成员的数组,如果是2个入口函数,则设置成员为3,最后一个成员的服务名和入口函数都要设置为NULL
// Service Start Table
//typedef struct _SERVICE_TABLE_ENTRYA {LPSTR lpServiceName; //服务名LPSERVICE_MAIN_FUNCTIONA lpServiceProc; //服务程序入口函数
}SERVICE_TABLE_ENTRYA, *LPSERVICE_TABLE_ENTRYA;
typedef struct _SERVICE_TABLE_ENTRYW {LPWSTR lpServiceName;LPSERVICE_MAIN_FUNCTIONW lpServiceProc;
}SERVICE_TABLE_ENTRYW, *LPSERVICE_TABLE_ENTRYW;
#ifdef UNICODE
typedef SERVICE_TABLE_ENTRYW SERVICE_TABLE_ENTRY;
typedef LPSERVICE_TABLE_ENTRYW LPSERVICE_TABLE_ENTRY;
#else
typedef SERVICE_TABLE_ENTRYA SERVICE_TABLE_ENTRY;
typedef LPSERVICE_TABLE_ENTRYA LPSERVICE_TABLE_ENTRY;
#endif // UNICODE
在main主函数中启动一个线程,用于创建一个新的线程
//定义并初始化一个服务入口函数表
SERVICE_TABLE_ENTRY DispatchTable[2];
DispatchTable[0].lpServiceName = “zcm_service0”;
DispatchTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain0;
DispatchTable[1].lpServiceName = NULL;//“zcm_service1”;
DispatchTable[1].lpServiceProc = NULL;//(LPSERVICE_MAIN_FUNCTION)ServiceMain1;
//根据服务入口函数表,创建一个新的线程
StartServiceCtrlDispatcher(DispatchTable);
下而是实例程序
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define SLEEP_TIME 5000
#define LOG_FILE_NAME "C:\\Documents and Settings\\Administrator\\My Documents\\visual studio 2010\\Projects\\zcm_service\\Debug\\debug.log"BOOL bRunning = TRUE;//是否运行,控制主函数
SERVICE_STATUS m_ServiceStatus; //服务状态结构
SERVICE_STATUS_HANDLE m_ServiceStatusHandle; //服务状态句柄void WINAPI ServiceMain0(int argc,char* argv[]);
//void WINAPI ServiceMain1(int argc,char* argv[]);void ServiceCtrlHandler0(DWORD Opcode);
//void ServiceCtrlHandler1(DWORD Opcode);void WriteToLog(LPTSTR szStr);int main(int argc,char* argv[])
{//创建服务程序入口函数表SERVICE_TABLE_ENTRY DispatchTable[2];DispatchTable[0].lpServiceName = "zcm_service0";DispatchTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain0;DispatchTable[1].lpServiceName = NULL;//"zcm_service1";DispatchTable[1].lpServiceProc = NULL;//(LPSERVICE_MAIN_FUNCTION)ServiceMain1;//DispatchTable[2].lpServiceName = NULL;//DispatchTable[2].lpServiceProc = NULL;//创建一个新的线程StartServiceCtrlDispatcher(DispatchTable);return 0;
}//服务入口主函数
void WINAPI ServiceMain0(int argc,char* argv[])
{MEMORYSTATUS memstatus;TCHAR szBuffer[256];int avaible_MB = 0;memset(szBuffer,0,256);//初始化服务状态m_ServiceStatus.dwServiceType = SERVICE_WIN32;m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_PAUSE_CONTINUE;m_ServiceStatus.dwWin32ExitCode = 0;m_ServiceStatus.dwServiceSpecificExitCode = 0;m_ServiceStatus.dwCheckPoint = 0;m_ServiceStatus.dwWaitHint = 0;//注册服务状态控制函数m_ServiceStatusHandle = RegisterServiceCtrlHandler("zcm_service0",(LPHANDLER_FUNCTION)ServiceCtrlHandler0);if(m_ServiceStatusHandle == 0){WriteToLog("RegisterServiceCtrlHandler ERROR!");return;}else{WriteToLog("RegisterServiceCtrlHandler OK!");}//修改服务状态m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;//报告运行状态到mcSetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);bRunning = TRUE;while(bRunning){//服务程序的主体GlobalMemoryStatus(&memstatus);avaible_MB = memstatus.dwAvailPhys / 1024 /1024;wsprintf(szBuffer,"Memory:%d",avaible_MB);WriteToLog(szBuffer);Sleep(SLEEP_TIME);}//bRunning = FALSEm_ServiceStatus.dwCurrentState = SERVICE_STOP;SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);WriteToLog("Program is Stoped!");return;
}//服务控制函数
//启动、停止、暂停、恢复操作,对这些功能进行操作
void ServiceCtrlHandler0(DWORD Opcode)
{switch(Opcode){case SERVICE_CONTROL_STOP:bRunning = FALSE;m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;break;case SERVICE_CONTROL_SHUTDOWN:bRunning = FALSE;m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;break;default:break;}SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);
}void WriteToLog(LPSTR szStr)
{FILE* fp;fopen_s(&fp,LOG_FILE_NAME,"a+");if(!fp){return ;}fprintf(fp,"%s\n",szStr);fclose(fp);
}