下面是在 VS2019 中使用 C++ 创建 Windows 服务程序基础框架的完整详细步骤。
一、创建项目
- 打开 VS2019 → 点击"创建新项目"
- 选择 "Windows 桌面向导" (Windows Desktop Wizard)
- 如果找不到,在搜索框输入 "desktop wizard"
- 配置项目:
- 项目名称:
MyWindowsService - 位置:选择你的目录
- 勾选"将解决方案和项目放在同一目录中"(可选)
- 项目名称:
- 点击"创建"
- 在弹出窗口中配置:
- 应用程序类型 :
控制台应用程序 (.exe) - 附加选项 :勾选
空项目 - 取消勾选"预编译头"
- 应用程序类型 :
- 点击"确定"
二、添加源文件
- 在解决方案资源管理器中,右键点击"源文件" → 添加 → 新建项
- 选择 C++ 文件 (.cpp)
- 名称:
ServiceMain.cpp - 点击"添加"
三、编写完整服务代码
cpp
#pragma warning(disable: 4996)
// ServiceMain.cpp
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <commdlg.h>
#include <shlobj.h>
#include <tlhelp32.h>
#include <vector>
#pragma comment(lib, "comdlg32.lib")
#pragma comment(lib, "shell32.lib")
// 服务名称(使用宽字符)
#define SERVICE_NAME L"AYUPanVirusScan"
#define SERVICE_DISPLAY_NAME L"AYUPanVirusScan"
#define SERVICE_DESCRIPTION L"专杀指定U盘病毒程序"
// 全局变量
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_ServiceStatusHandle = NULL;
HANDLE g_StopEvent = NULL; // 用于通知服务停止的事件
// 函数声明
void WINAPI ServiceMain(DWORD argc, LPWSTR* argv);
void WINAPI ServiceCtrlHandler(DWORD ctrlCode);
void ReportServiceStatus(DWORD currentState, DWORD exitCode, DWORD waitHint);
BOOL InstallService();
BOOL UninstallService();
void ServiceWorker(); // 实际工作函数
void WriteToLog(const char* message); // 日志记录
void WriteToLogW(const wchar_t* message); // 宽字符日志记录
std::string GetExeDirectory() {
char buffer[MAX_PATH];
GetModuleFileNameA(NULL, buffer, MAX_PATH);
// 获取文件路径后,去除文件名,只保留目录
std::string exePath(buffer);
size_t lastSlash = exePath.find_last_of("\\/");
if (lastSlash != std::string::npos) {
return exePath.substr(0, lastSlash);
}
return "";
}
// 写日志到文件(ANSI版本)
void WriteToLog(const char* message) {
std::string logPath = GetExeDirectory();
logPath = logPath + "\\ServiceLog.txt";
FILE* log = fopen(logPath.c_str(), "a");
if (log) {
SYSTEMTIME st;
GetLocalTime(&st);
fprintf(log, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond,
message);
fclose(log);
}
}
// 写日志到文件(宽字符版本)
void WriteToLogW(const wchar_t* message) {
char logPath[MAX_PATH];
GetCurrentDirectoryA(MAX_PATH, logPath);
strcat_s(logPath, "\\ServiceLog.txt");
FILE* log = fopen(logPath, "a");
if (log) {
SYSTEMTIME st;
GetLocalTime(&st);
fprintf(log, "[%04d-%02d-%02d %02d:%02d:%02d] ",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond);
// 转换宽字符到多字节
char buffer[1024];
WideCharToMultiByte(CP_ACP, 0, message, -1, buffer, sizeof(buffer), NULL, NULL);
fprintf(log, "%s\n", buffer);
fclose(log);
}
}
// 终止进程
static BOOL TerminateProcessByID(DWORD dwProcessID, UINT uExitCode = 0) {
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessID);
if (hProcess == NULL) {
char errorMsg[256];
sprintf_s(errorMsg, "OpenProcess failed, error code: %d", GetLastError());
WriteToLog(errorMsg);
return FALSE;
}
BOOL bResult = TerminateProcess(hProcess, uExitCode);
if (!bResult) {
char errorMsg[256];
sprintf_s(errorMsg, "TerminateProcess failed, error code: %d", GetLastError());
WriteToLog(errorMsg);
}
CloseHandle(hProcess);
return bResult;
}
// 按进程名杀死进程
bool KillProgressByName(std::wstring name) {
bool bExisted = false;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return false;
}
PROCESSENTRY32W pe = { sizeof(PROCESSENTRY32W) };
if (Process32FirstW(hSnapshot, &pe)) {
do {
if (wcscmp(pe.szExeFile, name.c_str()) == 0) {
bExisted = true;
char logMsg[512];
sprintf_s(logMsg, "Terminating process: %ls (PID: %d)", pe.szExeFile, pe.th32ProcessID);
WriteToLog(logMsg);
TerminateProcessByID(pe.th32ProcessID);
}
} while (Process32NextW(hSnapshot, &pe));
}
CloseHandle(hSnapshot);
return bExisted;
}
//实际工作函数
void Work() {
// 杀死指定的进程
if (KillProgressByName(L"FacialFeatureDemo.exe")) {
WriteToLog("Successfully terminated FacialFeatureDemo.exe");
}
}
// 工作线程的实际业务逻辑
void ServiceWorker() {
WriteToLog("Service worker thread started");
// 等待停止信号
while (WaitForSingleObject(g_StopEvent, 0) == WAIT_TIMEOUT) {
WriteToLog("Service is running... checking for FacialFeatureDemo.exe");
Work();
// 每5秒检查一次
Sleep(5000);
}
WriteToLog("Service worker thread stopped");
}
// 向SCM报告服务状态
void ReportServiceStatus(DWORD currentState, DWORD exitCode, DWORD waitHint) {
g_ServiceStatus.dwCurrentState = currentState;
g_ServiceStatus.dwWin32ExitCode = exitCode;
g_ServiceStatus.dwWaitHint = waitHint;
if (currentState == SERVICE_START_PENDING)
g_ServiceStatus.dwControlsAccepted = 0;
else
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
}
// 服务控制处理器(处理停止等命令)
void WINAPI ServiceCtrlHandler(DWORD ctrlCode) {
switch (ctrlCode) {
case SERVICE_CONTROL_STOP:
WriteToLog("Received STOP control code");
ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 3000);
// 通知工作线程停止
SetEvent(g_StopEvent);
ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
WriteToLog("Service stopped");
break;
case SERVICE_CONTROL_INTERROGATE:
ReportServiceStatus(g_ServiceStatus.dwCurrentState, NO_ERROR, 0);
break;
default:
break;
}
}
// 服务主入口(由SCM调用)
void WINAPI ServiceMain(DWORD argc, LPWSTR* argv) {
WriteToLog("ServiceMain entered");
// 注册服务控制处理器
g_ServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (!g_ServiceStatusHandle) {
WriteToLog("RegisterServiceCtrlHandler failed");
return;
}
// 创建停止事件(用于线程同步)
g_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!g_StopEvent) {
WriteToLog("CreateEvent failed");
return;
}
// 初始化服务状态
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwWin32ExitCode = NO_ERROR;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 5000;
ReportServiceStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
// 初始化工作
WriteToLog("Service initializing...");
//Sleep(1000); // 模拟初始化时间
// 创建工作线程
WriteToLog("worker thread start...");
std::thread worker(ServiceWorker);
worker.detach(); // 分离线程,让它在后台运行
// 服务已启动
ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 0);
WriteToLog("Service started successfully");
// 主线程等待停止事件
WaitForSingleObject(g_StopEvent, INFINITE);
// 清理资源
CloseHandle(g_StopEvent);
WriteToLog("ServiceMain exiting");
}
// 安装服务
BOOL InstallService() {
SC_HANDLE schSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!schSCManager) {
WriteToLog("OpenSCManager failed");
return FALSE;
}
// 获取当前exe路径(宽字符版本)
wchar_t modulePathW[MAX_PATH];
GetModuleFileNameW(NULL, modulePathW, MAX_PATH);
SC_HANDLE schService = CreateServiceW(
schSCManager,
SERVICE_NAME, // 服务名称
SERVICE_DISPLAY_NAME, // 显示名称
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, // 自动启动
SERVICE_ERROR_NORMAL,
modulePathW, // 程序路径
NULL, NULL, NULL, NULL, NULL
);
if (!schService) {
char errorMsg[256];
sprintf_s(errorMsg, "CreateService failed, error code: %d", GetLastError());
WriteToLog(errorMsg);
CloseServiceHandle(schSCManager);
return FALSE;
}
// 设置服务描述
SERVICE_DESCRIPTIONW sd;
sd.lpDescription = (LPWSTR)SERVICE_DESCRIPTION;
ChangeServiceConfig2W(schService, SERVICE_CONFIG_DESCRIPTION, &sd);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
WriteToLog("Service installed successfully");
return TRUE;
}
// 卸载服务
BOOL UninstallService() {
SC_HANDLE schSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if (!schSCManager) {
WriteToLog("OpenSCManager failed");
return FALSE;
}
SC_HANDLE schService = OpenServiceW(schSCManager, SERVICE_NAME, DELETE);
if (!schService) {
char errorMsg[256];
sprintf_s(errorMsg, "OpenService failed, error code: %d", GetLastError());
WriteToLog(errorMsg);
CloseServiceHandle(schSCManager);
return FALSE;
}
BOOL ret = DeleteService(schService);
if (ret) {
WriteToLog("Service uninstalled successfully");
wprintf(L"Service uninstalled successfully!\n");
}
else {
char errorMsg[256];
sprintf_s(errorMsg, "DeleteService failed, error code: %d", GetLastError());
WriteToLog(errorMsg);
wprintf(L"Service uninstallation failed (error: %d)\n", GetLastError());
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return ret;
}
//是否是服务程序
bool IsRunningAsService() {
DWORD sessionId = 0;
if (ProcessIdToSessionId(GetCurrentProcessId(), &sessionId)) {
// Session 0 是服务,其他是用户程序
return (sessionId == 0);
}
return false;
}
// 主函数(使用 wmain 以支持 Unicode)
int wmain(int argc, wchar_t* argv[]) {
WriteToLog("Main function started");
// 处理命令行参数
if (argc > 1) {
if (wcscmp(argv[1], L"install") == 0) {
if (InstallService()) {
wprintf(L"Service installed successfully!\n");
WriteToLog("Service installation completed");
}
else {
wprintf(L"Service installation failed (error: %d)\n", GetLastError());
WriteToLog("Service installation failed");
}
return 0;
}
else if (wcscmp(argv[1], L"uninstall") == 0) {
if (UninstallService()) {
wprintf(L"Service uninstalled successfully!\n");
WriteToLog("Service uninstallation completed");
}
else {
wprintf(L"Service uninstallation failed (error: %d)\n", GetLastError());
WriteToLog("Service uninstallation failed");
}
return 0;
}
else {
wprintf(L"Usage: %s [install|uninstall]\n", argv[0]);
return 0;
}
}
// 如果不是服务程序,则按程序台程序执行
if (!IsRunningAsService()) {
WriteToLog("控制台程序运行一次");
Work();
return 0;
}
// 作为服务运行
SERVICE_TABLE_ENTRYW serviceTable[] = {
{ (LPWSTR)SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONW)ServiceMain },
{ NULL, NULL }
};
WriteToLog("Starting service dispatcher");
if (!StartServiceCtrlDispatcherW(serviceTable)) {
DWORD error = GetLastError();
char errorMsg[256];
sprintf_s(errorMsg, "StartServiceCtrlDispatcher failed, error code: %d", error);
WriteToLog(errorMsg);
wprintf(L"Error: %d\n", error);
return 1;
}
WriteToLog("Service dispatcher exited");
return 0;
}
四、项目配置
由于使用了 C++ 标准库的 thread,需要确保项目设置正确:
- 右键点击项目 → 属性
- 配置属性 → C/C++ → 语言
- C++ 语言标准 :
ISO C++17 标准 (/std:c++17)
- C++ 语言标准 :
- 配置属性 → 链接器 → 系统
- 子系统 :
控制台 (/SUBSYSTEM:CONSOLE)- 注意:虽然是控制台程序,但作为服务运行时不会有控制台窗口
- 子系统 :
- 点击"确定"
五、编译项目
- 生成 → 生成解决方案 (Ctrl+Shift+B)
- 选择 Release 或 Debug 配置
- 编译成功后会生成
MyWindowsService.exe
六、安装和运行服务
1. 以管理员身份打开命令提示符
- 按 Win键,输入
cmd - 右键点击"命令提示符",选择"以管理员身份运行"
2. 导航到项目输出目录
cmd
cd "你的项目路径\MyWindowsService\Release"
3. 安装服务
cmd
MyWindowsService.exe install
看到 "Service installed successfully!" 表示安装成功。
4. 在服务管理器中查看和启动
方法一:使用服务管理器
- 按
Win + R,输入services.msc,回车 - 找到
My Sample Windows Service - 右键 → 启动
方法二:使用命令行
cmd
sc start MySampleService
5. 验证服务运行
检查日志文件:
- 打开项目目录(exe所在目录)
- 找到
ServiceLog.txt文件 - 查看日志内容,应该看到服务运行记录
6. 停止服务
cmd
sc stop MySampleService
7. 卸载服务(可选)
cmd
MyWindowsService.exe uninstall
七、调试技巧
方法1:直接调试(模拟运行)
由于服务不能直接双击运行,可以临时修改代码便于调试:
cpp
int main(int argc, char* argv[]) {
// 调试模式下直接运行工作逻辑
#ifdef _DEBUG
WriteToLog("Running in debug mode");
ServiceWorker(); // 直接调用工作函数
return 0;
#endif
// 正常服务代码...
}
方法2:附加到进程调试
- 安装并启动服务
- VS2019中:调试 → 附加到进程
- 找到
MyWindowsService.exe,附加 - 在代码中设置断点
方法3:使用日志输出
代码中已经集成了 WriteToLog 函数,可以记录关键步骤。
八、常见问题解决
| 问题 | 解决方案 |
|---|---|
| 安装失败(错误5) | 必须以管理员身份运行命令提示符 |
| 启动后立即停止 | 检查日志文件,查看错误信息 |
| 找不到日志文件 | 日志写在exe所在目录,检查目录权限 |
| 编译错误 C4996 | 项目属性 → C/C++ → 预处理器 → 添加 _CRT_SECURE_NO_WARNINGS |
| 服务启动超时 | dwWaitHint 设置更大的值(如30000) |
九、生产环境建议
- 使用事件等待 :不要用
while + Sleep,应该用WaitForSingleObject等待停止事件 - 添加配置读取:从注册表或配置文件读取服务参数
- 完善错误处理:所有 API 调用都要检查返回值
- 添加性能监控:记录服务响应时间、内存使用等
- 实现服务恢复:配置服务失败后的恢复操作(重启、运行程序等)
这个基础框架可以直接在 VS2019 中编译使用,你可以根据实际需求扩展业务逻辑。