Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。这种服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。
一.一个简单的Windows服务
#include <iostream>
#include <Windows.h>
#include <winsvc.h>
#include <string>
#pragma comment (lib,"Advapi32.lib")
#define SERVICE_NAME "TestService"
#define SERVICE_DESC "TestService cao shang pa"
SERVICE_STATUS gServiceStatus;
SERVICE_STATUS_HANDLE gServiceStatusHandle;
HANDLE gServiceStopEvent = NULL;
void WINAPI ServiceMain(int argc, char** argv);
void WINAPI ServiceCtrlHandler(DWORD request);
void ReportServiceStatus(DWORD CurrentStatus, DWORD Win32ExitCode, DWORD WaitHint);
void WINAPI ServiceMain(int argc, char** argv)
{
gServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (!gServiceStatusHandle)
{
std::cout<<"RegisterServiceCtrlHandler failed"<<std::endl;
OutputDebugString("RegisterServiceCtrlHandler failed");
return;
}
std::cout<<"RegisterServiceCtrlHandler succeed"<<std::endl;
OutputDebugString("RegisterServiceCtrlHandler succeed");
//向SCM 报告运行状态.
ReportServiceStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
OutputDebugString("Service starting...");
//在此处添加你自己希望服务做的工作,
// TODO
gServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!gServiceStopEvent)
{
ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
OutputDebugString("Service stopped");
return;
}
else
{
ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 0);
OutputDebugString("Service running...");
}
WaitForSingleObject(gServiceStopEvent, INFINITE);
ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
OutputDebugString("Service stopped");
}
void WINAPI ServiceCtrlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP:
ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
OutputDebugString("Service stopping...");
SetEvent(gServiceStopEvent);
return;
case SERVICE_CONTROL_SHUTDOWN:
break;
default:
break;
}
ReportServiceStatus(gServiceStatus.dwCurrentState, NO_ERROR, 0);
}
void ReportServiceStatus(DWORD CurrentStatus, DWORD Win32ExitCode, DWORD WaitHint)
{
static DWORD nCheckPoint = 1;
gServiceStatus.dwServiceType = SERVICE_WIN32;
gServiceStatus.dwCurrentState = CurrentStatus;
gServiceStatus.dwWin32ExitCode = Win32ExitCode;
gServiceStatus.dwWaitHint = WaitHint;
if (CurrentStatus == SERVICE_START_PENDING)
{
gServiceStatus.dwControlsAccepted = 0;
}
else
{
gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
}
if ((CurrentStatus == SERVICE_RUNNING) || (CurrentStatus == SERVICE_STOPPED))
{
gServiceStatus.dwCheckPoint = 0;
}
else
{
gServiceStatus.dwCheckPoint = nCheckPoint++;
}
gServiceStatus.dwServiceSpecificExitCode = 0;
SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
}
int main(int argc, char *argv[])
{
SERVICE_TABLE_ENTRY entrytable[2];
entrytable[0].lpServiceName = const_cast<char *>(std::string(SERVICE_NAME).c_str());
entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
entrytable[1].lpServiceName = NULL;
entrytable[1].lpServiceProc = NULL;
// 也可以写成下面这种形式.
// SERVICE_TABLE_ENTRY entrytable[] =
// {
// {
// SERVICE_NAME,
// (LPSERVICE_MAIN_FUNCTION)ServiceMain
// },
// {
// NULL,
// NULL
// }
// };
if (!StartServiceCtrlDispatcher(entrytable))
{
std::cout<<"StartServiceCtrlDispatcher failed";
OutputDebugString("StartServiceCtrlDispatcher failed");
}
return 0;
}
代码很简单,api手册上都可以查到,需要注意的一点是ServiceMain函数是服务的入口点,它运行在一个单独的线程当中,这个线程是由控制分派器创建的。
下面是一些服务相关的操作
// 创建服务,注意"="后面有一个空格
sc create TestService binpath= C:\Users\zhang\Desktop\TestService\out\TestService.exe
// 启动服务器
sc start TestService
// 查询服务当前状态
sc query TestService
// 停止服务
sc stop TestService
// 删除服务
sc delete TestService
下面是安装服务的脚本InstallService.bat
@echo off
rem 获取绝对路径
set "CURRENT_DIR=%~dp0"
set "EXE_NAME=TestService.exe"
@echo %CURRENT_DIR%%EXE_NAME%
rem 创建windows服务
sc create TestService binpath= %CURRENT_DIR%%EXE_NAME%
sc config TestService start=AUTO
sc start TestService
下面是卸载服务的脚本UninstallService.bat
@echo off
rem 获取绝对路径
set "CURRENT_DIR=%~dp0"
set "EXE_NAME=TestService.exe"
@echo %CURRENT_DIR%%EXE_NAME%
rem 删除windows服务
sc stop TestService
sc delete TestService
当然也可以在代码中完成InstallService.bat和UninstallService.bat这两个脚本的功能
int InstallService()
{
if (IsInstalled())
{
std::cout<<"Service already installed"<<std::endl;
OutputDebugString("Service already installed");
return 0;
}
//打开服务控制管理器.
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
std::cout<<"OpenSCManager failed"<<std::endl;
OutputDebugString("OpenSCManager failed");
return -1;
}
// Get the executable file path
TCHAR szFilePath[MAX_PATH];
GetModuleFileName(NULL, szFilePath, MAX_PATH);
//创建服务,并设置服务自动启动.
SC_HANDLE hService = CreateService(
hSCM, SERVICE_NAME, SERVICE_NAME,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, NULL, NULL, NULL);
if (hService == NULL)
{
CloseServiceHandle(hSCM);
std::cout<<"CreateService failed"<<std::endl;
OutputDebugString("CreateService failed");
return -1;
}
//设置服务描述(在服务列表中可与看到)
SERVICE_DESCRIPTION Description;
TCHAR szDescription[1024];
ZeroMemory(szDescription, 0);
ZeroMemory(&Description, sizeof (SERVICE_DESCRIPTION));
lstrcpy(szDescription, SERVICE_DESC);
Description.lpDescription = szDescription;
ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &Description);
if (StartService(hService, 0, NULL) == FALSE)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
std::cout<<"StartService failed"<<std::endl;
OutputDebugString("StartService failed");
return -1;
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
std::cout<<"Install service succeed"<<std::endl;
OutputDebugString("Install service succeed");
return 0;
}
int UninstallService()
{
if (!IsInstalled())
{
std::cout<<"Service not installed"<<std::endl;
OutputDebugString("Service not installed");
return 0;
}
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
std::cout<<"OpenSCManager failed"<<std::endl;
OutputDebugString("OpenSCManager failed");
return -1;
}
SC_HANDLE hService = OpenService(hSCM, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_STOP | DELETE);
if (hService == NULL)
{
CloseServiceHandle(hSCM);
std::cout<<"OpenService failed"<<std::endl;
OutputDebugString("OpenService failed");
return -1;
}
SERVICE_STATUS status;
if (QueryServiceStatus(hService, &status) == FALSE)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
std::cout<<"QueryServiceStatus failed"<<std::endl;
OutputDebugString("QueryServiceStatus failed");
return -1;
}
if (status.dwCurrentState == SERVICE_RUNNING)
{
if (ControlService(hService, SERVICE_CONTROL_STOP, &status) == FALSE)
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
std::cout<<"Stop Service failed"<<std::endl;
OutputDebugString("Stop Service failed");
return -1;
}
}
//如果服务状态为已停止,则卸载该系统服务.
if (status.dwCurrentState == SERVICE_STOPPED)
{
//删除服务.
BOOL bDelete = DeleteService(hService);
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
if (bDelete)
{
std::cout<<"Uninstall service succeed"<<std::endl;
OutputDebugString("Uninstall service succeed");
return 0;
}
else
{
std::cout<<"Uninstall service failed"<<std::endl;
OutputDebugString("Uninstall service failed");
return -1;
}
}
return -1;
}
然后把main函数也改一下
int main(int argc, char *argv[])
{
if (argc == 2)
{
if (strcmp(argv[1], "-install") == 0)
{
InstallService();
}
else if (strcmp(argv[1], "-uninstall") == 0)
{
UninstallService();
}
}
else
{
SERVICE_TABLE_ENTRY entrytable[2];
entrytable[0].lpServiceName = const_cast<char *>(std::string(SERVICE_NAME).c_str());
entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
entrytable[1].lpServiceName = NULL;
entrytable[1].lpServiceProc = NULL;
// 也可以写成下面这种形式.
// SERVICE_TABLE_ENTRY entrytable[] =
// {
// {
// SERVICE_NAME,
// (LPSERVICE_MAIN_FUNCTION)ServiceMain
// },
// {
// NULL,
// NULL
// }
// };
if (!StartServiceCtrlDispatcher(entrytable))
{
std::cout<<"StartServiceCtrlDispatcher failed";
OutputDebugString("StartServiceCtrlDispatcher failed");
}
}
return 0;
}
这样就能用下面的指令来安装和卸载服务了
TestService -install
TestService -uninstall
二.DebugView调试工具
我们可以用这款软件来调试windows服务程序,代码中用OutputDebugString打印调试信息,DebugView就能捕获并显示出来
如下图所示,把能勾的都勾上
原文链接:https://blog.csdn.net/caoshangpa/article/details/79475677