windows服务程序的编写
2015-06-09 17:55
274 查看
windows服务程序可以设置为开机运行,具有特权。一个服务程序编写完成后要进行安装,然后通过本地服务的管理工具打开,当然如果设置为开机自动运行就不用手动开启了。服务程序不应该双击运行。
windows服务程序需要进行安装,,也可以在服务程序的入口函数接收传入的参数,然后进行判断是否进行安装,判断接收的参数是什么字符串,然后再程序内进行安装,这个时候,服务还没有被注册,也没有被安装,程序只能算是一个普通应用程序。安装之后就不应该双击运行了,要通过本地服务管理工具打开或者开机启动。
#define SERVER_NAME "MyTestServer"
//内部变量
bool bDebugServer=false;
SERVICE_STATUS ssStatus;
SERVICE_STATUS_HANDLE hService;
DWORD dwErr=0;
TCHAR szErr[256];
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = CoInitialize(NULL);
if((argc>1) && ((argv[1][0] == _T('-')) || (argv[1][0] == _T('/'))))
{
if(_tcsicmp(_T("install"), argv[1]+1)==0)
{
installService();
}
else if(_tcsicmp(_T("remove"), argv[1]+1)==0)
{
removeService();
}
else if(_tcsicmp(_T("debug"), argv[1]+1)==0)
{
//bDebugServer=true;
//debugService(argc, argv);
}
return 0;
}
SERVICE_TABLE_ENTRY st[] =
{
{ _T(SERVER_NAME), Service_Main },
{ NULL, NULL }
};
StartServiceCtrlDispatcher(st);//通过指定的Service_Main 程序会跳转到Service_Main 去执行,如果失败,可能是因为程序不是用过windows服务管理器打开的。
//安装的时候通过CreateService可以设置开机自动启动。
CoUninitialize();
return 0;
}
//安装服务程序
void installService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
TCHAR szPath[512];
//得到程序磁盘文件的路径
GetModuleFileName(NULL,szPath,512);
AppendDbgMsg("install service \r\n");//AppendDbgMsg是我自己写的写文件操作的函数,以免在没有界面的情况下不知道具体执行情况。
//打开服务管理数据库
schSCManager=OpenSCManager(
NULL, //本地计算机
NULL, //默认的数据库
SC_MANAGER_ALL_ACCESS //要求所有的访问权
);
if(schSCManager)
{
//登记服务程序
schService=CreateService(
schSCManager, //服务管理数据库句柄
TEXT(SERVER_NAME), //服务名
TEXT(SERVER_NAME), //用于显示服务的标识
SERVICE_ALL_ACCESS, //响应所有的访问请求
SERVICE_WIN32_OWN_PROCESS, //服务类型
SERVICE_AUTO_START, //启动类型 //设置为Auto就会开机自动启动
SERVICE_ERROR_NORMAL, //错误控制类型
szPath, //服务程序磁盘文件的路径
NULL, //服务不属于任何组
NULL, //没有tag标识符
NULL, //启动服务所依赖的服务或服务组,这里仅仅是一个空字符串
NULL, //LocalSystem 帐号
NULL);
if(schService)
{
AppendDbgMsg("%s installed. \n", SERVER_NAME);
CloseServiceHandle(schService);
}
else
{
AppendDbgMsg("CreateService failed - %d \n", GetLastError());
}
CloseServiceHandle(schSCManager);
}
else
{
AppendDbgMsg("OpenSCManager failed - %d \n", GetLastError());
}
}
//停止和删除已安装的服务程序
void removeService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
AppendDbgMsg("remove service \r\n");
//打开服务管理数据库
schSCManager=OpenSCManager(
NULL, //本地计算机
NULL, //默认的数据库
SC_MANAGER_ALL_ACCESS //要求所有的访问权
);
if(schSCManager)
{
//获取服务程序句柄
schService=OpenService(
schSCManager, //服务管理数据库句柄
TEXT(SERVER_NAME), //服务名
SERVICE_ALL_ACCESS //响应所有的访问请求
);
if(schService)
{
//试图停止服务
if(ControlService(
schService, //服务程序句柄
SERVICE_CONTROL_STOP, //停止服务请求码
&ssStatus //接收最后的服务状态信息
))
{
AppendDbgMsg("Stopping %s.", SERVER_NAME);
Sleep(1000);
//等待服务停止
//
while(QueryServiceStatus(schService,&ssStatus))
{
if(SERVICE_STOP_PENDING==ssStatus.dwCurrentState)
{
AppendDbgMsg(".");
Sleep(1000);
}
else
break;
}
if(SERVICE_STOPPED==ssStatus.dwCurrentState)
{
AppendDbgMsg("\n %s stopped. \n", SERVER_NAME);
}
else
{
AppendDbgMsg("\n %s failed to stopp. \n", SERVER_NAME);
}
}
//删除已安装的服务程序安装
if(DeleteService(schService))
{
AppendDbgMsg("%s removed. \n", SERVER_NAME);
}
else
{
AppendDbgMsg("DeleteService failed - %d. \n", GetLastError());
}
CloseServiceHandle(schService);
}
else
{
AppendDbgMsg("OpenService failed - %d \n", GetLastError());
}
CloseServiceHandle(schSCManager);
}
else
{
AppendDbgMsg("OpenSCManager failed - %d \n", GetLastError());
}
}
//服务的入口
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
{
AppendDbgMsg("in server main gonna to register server control handle \r\n");
//注册服务控制处理函数
hService = RegisterServiceCtrlHandler(TEXT(SERVER_NAME), Service_Ctrl);//消息会通过Service_Ctrl传入,然后再函数中处理
//如果注册失败
if(!hService)
{
AppendDbgMsg("register failed \r\n");
goto cleanup;
return;
}
else
{
AppendDbgMsg("success to register \r\n");
}
//初始化 SERVICE_STATUS 结构中的成员
ssStatus.dwCurrentState = SERVICE_RUNNING;
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwServiceSpecificExitCode = 0;
//更新服务状态
if(!ReportStatusToSCMgr(
SERVICE_RUNNING,//服务状态,The service is starting.
NO_ERROR, //退出码
3000)) //等待时间
{
goto cleanup; //更新服务状态失败则转向 cleanup
}
ServiceStart(dwArgc, lpszArgv);/服务启动之后执行的函数,不一定要设置为函数。可以直接写代码
return;
cleanup:
//把服务状态更新为 SERVICE_STOPPED,并退出。
if(hService)
{
(void)ReportStatusToSCMgr(SERVICE_STOPPED, dwErr, 0);
}
}
//消息处理函数
void WINAPI Service_Ctrl(DWORD dwCtrlCode)
{
AppendDbgMsg("server control\r\n");
//处理控制请求码
switch(dwCtrlCode)
{
//先更新服务状态为 SERVICDE_STOP_PENDING,再停止服务。
case SERVICE_CONTROL_STOP:
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);
AppendDbgMsg("SERVICE_CONTROL_STOP");
//ServiceStop(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_STOPPED;
break;
}
//暂停服务
case SERVICE_CONTROL_PAUSE:
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);
AppendDbgMsg("SERVICE_CONTROL_PAUSE");
// ServicePause(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_PAUSED;
break;
}
//继续服务
case SERVICE_CONTROL_CONTINUE:
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);
AppendDbgMsg("SERVICE_CONTROL_CONTINUE");
// ServiceContinue(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_RUNNING;
break;
}
//更新服务状态
case SERVICE_CONTROL_INTERROGATE:
{
AppendDbgMsg("SERVICE_CONTROL_INTERROGATE");
break;
}
//无效控制码
default:
{
AppendDbgMsg("default");
break;
}
}
ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}
void WINAPI ServiceStart(DWORD dwArgc,LPTSTR *lpArgv)
{
HANDLE hThread;
//创建服务线程 服务完成的功能在这里调用
hThread = CreateThread(NULL,
0,
Service,
NULL,
0,
NULL);
if(hThread == NULL)
{
AppendDbgMsg("failed to create service thread \r\n");
return;
}
return;
}
//服务线程函数,其实什么都没做
DWORD WINAPI Service(LPVOID lpvThread)
{
while(1)
{
AppendDbgMsg("service thread \r\n");//这里可以用命名管道与普通应用程序进行通信,也可以通过读写文件进行通信,然后完成自己的任务
Sleep(30000);
}
return 0;
}
//初始化SERVICE_STATUS ,为了方便设置
void InitServiceState(SERVICE_STATUS *pStatus)
{
(*pStatus).dwServiceType = SERVICE_WIN32_OWN_PROCESS;
(*pStatus).dwCurrentState = SERVICE_STOPPED;
(*pStatus).dwControlsAccepted = SERVICE_ACCEPT_STOP;
(*pStatus).dwWin32ExitCode = 0;
(*pStatus).dwServiceSpecificExitCode = 0;
(*pStatus).dwCheckPoint = 0;
(*pStatus).dwWaitHint = 0;
}
//设置状态和返回值、延时
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
InitServiceState(&ssStatus);
ssStatus.dwCurrentState = dwCurrentState;
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
ssStatus.dwWaitHint = dwWaitHint;
return SetServiceStatus(hService, &ssStatus);
}
服务程序中的主函数中有一段用来识别传入参数的模块,如果参数是install就进行安装,所以最好写一个批处理,然后用管理员权限运行,就能安装了,代码如下:
set filedir=%~dp0
set file=%filedir%MyServer
start %file% -install
pause
安装完之后就可以在本地服务管理器中看到对应的名字,按win+R,输入services.msc就可以看到,任务管理器中也可以看到,但最好通过services.msc进行开启、停止。
因为设置的是开机启动,所以立即重启会看到调试文件中的信息(调试文件的写入函数要自己提供,可以不写)
windows服务程序需要进行安装,,也可以在服务程序的入口函数接收传入的参数,然后进行判断是否进行安装,判断接收的参数是什么字符串,然后再程序内进行安装,这个时候,服务还没有被注册,也没有被安装,程序只能算是一个普通应用程序。安装之后就不应该双击运行了,要通过本地服务管理工具打开或者开机启动。
#define SERVER_NAME "MyTestServer"
//内部变量
bool bDebugServer=false;
SERVICE_STATUS ssStatus;
SERVICE_STATUS_HANDLE hService;
DWORD dwErr=0;
TCHAR szErr[256];
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = CoInitialize(NULL);
if((argc>1) && ((argv[1][0] == _T('-')) || (argv[1][0] == _T('/'))))
{
if(_tcsicmp(_T("install"), argv[1]+1)==0)
{
installService();
}
else if(_tcsicmp(_T("remove"), argv[1]+1)==0)
{
removeService();
}
else if(_tcsicmp(_T("debug"), argv[1]+1)==0)
{
//bDebugServer=true;
//debugService(argc, argv);
}
return 0;
}
SERVICE_TABLE_ENTRY st[] =
{
{ _T(SERVER_NAME), Service_Main },
{ NULL, NULL }
};
StartServiceCtrlDispatcher(st);//通过指定的Service_Main 程序会跳转到Service_Main 去执行,如果失败,可能是因为程序不是用过windows服务管理器打开的。
//安装的时候通过CreateService可以设置开机自动启动。
CoUninitialize();
return 0;
}
//安装服务程序
void installService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
TCHAR szPath[512];
//得到程序磁盘文件的路径
GetModuleFileName(NULL,szPath,512);
AppendDbgMsg("install service \r\n");//AppendDbgMsg是我自己写的写文件操作的函数,以免在没有界面的情况下不知道具体执行情况。
//打开服务管理数据库
schSCManager=OpenSCManager(
NULL, //本地计算机
NULL, //默认的数据库
SC_MANAGER_ALL_ACCESS //要求所有的访问权
);
if(schSCManager)
{
//登记服务程序
schService=CreateService(
schSCManager, //服务管理数据库句柄
TEXT(SERVER_NAME), //服务名
TEXT(SERVER_NAME), //用于显示服务的标识
SERVICE_ALL_ACCESS, //响应所有的访问请求
SERVICE_WIN32_OWN_PROCESS, //服务类型
SERVICE_AUTO_START, //启动类型 //设置为Auto就会开机自动启动
SERVICE_ERROR_NORMAL, //错误控制类型
szPath, //服务程序磁盘文件的路径
NULL, //服务不属于任何组
NULL, //没有tag标识符
NULL, //启动服务所依赖的服务或服务组,这里仅仅是一个空字符串
NULL, //LocalSystem 帐号
NULL);
if(schService)
{
AppendDbgMsg("%s installed. \n", SERVER_NAME);
CloseServiceHandle(schService);
}
else
{
AppendDbgMsg("CreateService failed - %d \n", GetLastError());
}
CloseServiceHandle(schSCManager);
}
else
{
AppendDbgMsg("OpenSCManager failed - %d \n", GetLastError());
}
}
//停止和删除已安装的服务程序
void removeService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
AppendDbgMsg("remove service \r\n");
//打开服务管理数据库
schSCManager=OpenSCManager(
NULL, //本地计算机
NULL, //默认的数据库
SC_MANAGER_ALL_ACCESS //要求所有的访问权
);
if(schSCManager)
{
//获取服务程序句柄
schService=OpenService(
schSCManager, //服务管理数据库句柄
TEXT(SERVER_NAME), //服务名
SERVICE_ALL_ACCESS //响应所有的访问请求
);
if(schService)
{
//试图停止服务
if(ControlService(
schService, //服务程序句柄
SERVICE_CONTROL_STOP, //停止服务请求码
&ssStatus //接收最后的服务状态信息
))
{
AppendDbgMsg("Stopping %s.", SERVER_NAME);
Sleep(1000);
//等待服务停止
//
while(QueryServiceStatus(schService,&ssStatus))
{
if(SERVICE_STOP_PENDING==ssStatus.dwCurrentState)
{
AppendDbgMsg(".");
Sleep(1000);
}
else
break;
}
if(SERVICE_STOPPED==ssStatus.dwCurrentState)
{
AppendDbgMsg("\n %s stopped. \n", SERVER_NAME);
}
else
{
AppendDbgMsg("\n %s failed to stopp. \n", SERVER_NAME);
}
}
//删除已安装的服务程序安装
if(DeleteService(schService))
{
AppendDbgMsg("%s removed. \n", SERVER_NAME);
}
else
{
AppendDbgMsg("DeleteService failed - %d. \n", GetLastError());
}
CloseServiceHandle(schService);
}
else
{
AppendDbgMsg("OpenService failed - %d \n", GetLastError());
}
CloseServiceHandle(schSCManager);
}
else
{
AppendDbgMsg("OpenSCManager failed - %d \n", GetLastError());
}
}
//服务的入口
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
{
AppendDbgMsg("in server main gonna to register server control handle \r\n");
//注册服务控制处理函数
hService = RegisterServiceCtrlHandler(TEXT(SERVER_NAME), Service_Ctrl);//消息会通过Service_Ctrl传入,然后再函数中处理
//如果注册失败
if(!hService)
{
AppendDbgMsg("register failed \r\n");
goto cleanup;
return;
}
else
{
AppendDbgMsg("success to register \r\n");
}
//初始化 SERVICE_STATUS 结构中的成员
ssStatus.dwCurrentState = SERVICE_RUNNING;
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwServiceSpecificExitCode = 0;
//更新服务状态
if(!ReportStatusToSCMgr(
SERVICE_RUNNING,//服务状态,The service is starting.
NO_ERROR, //退出码
3000)) //等待时间
{
goto cleanup; //更新服务状态失败则转向 cleanup
}
ServiceStart(dwArgc, lpszArgv);/服务启动之后执行的函数,不一定要设置为函数。可以直接写代码
return;
cleanup:
//把服务状态更新为 SERVICE_STOPPED,并退出。
if(hService)
{
(void)ReportStatusToSCMgr(SERVICE_STOPPED, dwErr, 0);
}
}
//消息处理函数
void WINAPI Service_Ctrl(DWORD dwCtrlCode)
{
AppendDbgMsg("server control\r\n");
//处理控制请求码
switch(dwCtrlCode)
{
//先更新服务状态为 SERVICDE_STOP_PENDING,再停止服务。
case SERVICE_CONTROL_STOP:
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);
AppendDbgMsg("SERVICE_CONTROL_STOP");
//ServiceStop(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_STOPPED;
break;
}
//暂停服务
case SERVICE_CONTROL_PAUSE:
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);
AppendDbgMsg("SERVICE_CONTROL_PAUSE");
// ServicePause(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_PAUSED;
break;
}
//继续服务
case SERVICE_CONTROL_CONTINUE:
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 500);
AppendDbgMsg("SERVICE_CONTROL_CONTINUE");
// ServiceContinue(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_RUNNING;
break;
}
//更新服务状态
case SERVICE_CONTROL_INTERROGATE:
{
AppendDbgMsg("SERVICE_CONTROL_INTERROGATE");
break;
}
//无效控制码
default:
{
AppendDbgMsg("default");
break;
}
}
ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}
void WINAPI ServiceStart(DWORD dwArgc,LPTSTR *lpArgv)
{
HANDLE hThread;
//创建服务线程 服务完成的功能在这里调用
hThread = CreateThread(NULL,
0,
Service,
NULL,
0,
NULL);
if(hThread == NULL)
{
AppendDbgMsg("failed to create service thread \r\n");
return;
}
return;
}
//服务线程函数,其实什么都没做
DWORD WINAPI Service(LPVOID lpvThread)
{
while(1)
{
AppendDbgMsg("service thread \r\n");//这里可以用命名管道与普通应用程序进行通信,也可以通过读写文件进行通信,然后完成自己的任务
Sleep(30000);
}
return 0;
}
//初始化SERVICE_STATUS ,为了方便设置
void InitServiceState(SERVICE_STATUS *pStatus)
{
(*pStatus).dwServiceType = SERVICE_WIN32_OWN_PROCESS;
(*pStatus).dwCurrentState = SERVICE_STOPPED;
(*pStatus).dwControlsAccepted = SERVICE_ACCEPT_STOP;
(*pStatus).dwWin32ExitCode = 0;
(*pStatus).dwServiceSpecificExitCode = 0;
(*pStatus).dwCheckPoint = 0;
(*pStatus).dwWaitHint = 0;
}
//设置状态和返回值、延时
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
InitServiceState(&ssStatus);
ssStatus.dwCurrentState = dwCurrentState;
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
ssStatus.dwWaitHint = dwWaitHint;
return SetServiceStatus(hService, &ssStatus);
}
服务程序中的主函数中有一段用来识别传入参数的模块,如果参数是install就进行安装,所以最好写一个批处理,然后用管理员权限运行,就能安装了,代码如下:
set filedir=%~dp0
set file=%filedir%MyServer
start %file% -install
pause
安装完之后就可以在本地服务管理器中看到对应的名字,按win+R,输入services.msc就可以看到,任务管理器中也可以看到,但最好通过services.msc进行开启、停止。
因为设置的是开机启动,所以立即重启会看到调试文件中的信息(调试文件的写入函数要自己提供,可以不写)
相关文章推荐
- WinForm中DataGridView控件绑定列顺序
- 通用方法解决dedecms导航调用二级、三级栏目菜单
- 悯码农 * 慧哥
- python环境变量的配置
- 集合框架2
- Nuget管理我们的类库
- ASP.NET forms凭据设置和跳转的几种方法
- dedecms织梦导航栏二级菜单的实现方法
- 微信投票怎么刷票之微信怎么刷投票快速提升票数方法
- SQL Server-1
- 苹果三大系统更新 iOS 9有何亮点?
- MDT 2013 从入门到精通之Task部署任务创建
- Tiny工程可以配置多个application.xml吗
- 1163 最高的奖励
- Subsequence - HDU 3530 单调队列优化
- 安装elipse插件Genymotion是应该注意的问题
- signalR消息实时推送
- 定时器
- 软件架构杂谈(四) --- P2P
- SurfaceView播放视频遇到的bug