可以使用命令行方式进行安装、启动、停止、卸载,命令参数分别为:install、start、stop、uninstall,参数不区分大小写,可以加反斜杠“/”,也可以不加。
这个服务程序的功能是:服务测试程序。随机启动,启动时会将当前时间写入StartTime.txt文件,并将运行日志写入log文件夹。看参考服务描述。
程序运行很快,一般启动后就退出了,除非注释掉SetEvent功能。
整个工程源码下载:
[点击浏览该文件:StartTimeService.zip]
使用中,有几个小技巧说下。
如果想调试这个服务程序,那么就把ServiceMain函数中的Sleep(30000)启用(取消注释),然后“附加到进程”进行调试。
……………………
SetServiceStatus(hStatus,&ServiceStatus);
//暂停30秒,在这一句代码的后面下断点。
//在这段时间中,使用VC或者VS打开“附加到进程”,找到这个程序“StartTimeService.exe”,确定附加。
//时间到了,就中断了。
//如果不调试,请注释掉暂停代码。
//Sleep(30000);
//创建运行线程
……………………………………
如果想测试或调试“start”或“stop”命令,那么把ThreadMain函数的SetEvent注释去掉,不然程序运行很快,马上就退出了。
…………………………
EXIT0:
CloseHandle(hFile);
//自己在测试命令行的“start”和“stop”命令时,可以注释下面的一行,这样主线程就不会退出了。
//SetEvent(hEventEnd);
CSerCtrl.WriteToLog("ThreadMain结束!",sizeof("ThreadMain结束!"));
…………………………

源码有三个主要文件:StartTimeService.cpp,ServiceControl.cpp,ServiceControl.h
// StartTimeService.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
#include <Shlwapi.h>
#include "ServiceControl.h"
#pragma comment(lib,"shlwapi")
/*
本服务启动后,随机启动。
每次启动时,在程序目录下生成StartTime.txt文件,记录系统的启动时间
可以每天查看日志,就知道自己的电脑是否被开机过。
*/
TCHAR tzServiceName[] = _T("StartTimeService");
TCHAR tzServiceDescription[] = _T("服务测试程序。随机启动,启动时会将当前时间写入StartTime.txt文件,并将运行日志写入log文件夹。");
SERVICE_STATUS ServiceStatus = {0};
SERVICE_STATUS_HANDLE hStatus = NULL;
HANDLE hEventEnd = NULL; //服务是否结束事件
//声明服务函数
void WINAPI ServiceMain();
void WINAPI ServiceCtrlHandle(DWORD dwOpcode);
//线程函数
DWORD WINAPI ThreadMain(LPVOID pParam);
CServiceControl CSerCtrl(tzServiceName,tzServiceDescription);;
int _tmain(int argc, _TCHAR* argv[])
{
//设置日志路径,为空或者不调用的话,自动安装日期生成日志名
//CSerCtrl.SetLogFileName(NULL);
//CSerCtrl.SetLogFileName(_T("log.txt"));
if (argc == 2)
{
//安装
if (_tcsicmp(argv[1],_T("install")) == 0
|| _tcsicmp(argv[1],_T("/install")) == 0)
{
if (CSerCtrl.Install())
{
printf("服务安装成功!");
}
else
{
printf("服务安装失败!");
}
}
//卸载
if (_tcsicmp(argv[1],_T("uninstall")) == 0
|| _tcsicmp(argv[1],_T("/uninstall")) == 0)
{
if (CSerCtrl.UnInstall())
{
printf("服务卸载成功!");
}
else
{
printf("服务卸载失败!");
}
}
//启动
if (_tcsicmp(argv[1],_T("start")) == 0
|| _tcsicmp(argv[1],_T("/start")) == 0)
{
if (CSerCtrl.Start())
{
printf("服务启动成功!");
}
else
{
printf("服务启动失败!");
}
}
//停止
if (_tcsicmp(argv[1],_T("stop")) == 0
|| _tcsicmp(argv[1],_T("/stop")) == 0)
{
if (CSerCtrl.Stop())
{
printf("服务停止成功!");
}
else
{
printf("服务停止失败!");
}
}
}
else
{
//启动服务
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{tzServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL,NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == 0)
{
CSerCtrl.WriteToLog("Register Service Main Function Error!",sizeof("Register Service Main Function Error!"));
}
CSerCtrl.WriteToLog("StartServiceCtrlDispatcher成功!",sizeof("StartServiceCtrlDispatcher成功!"));
}
CSerCtrl.WriteToLog("_tmain结束!",sizeof("_tmain结束!"));
return 0;
}
void WINAPI ServiceMain()
{
HANDLE hThread = NULL;
DWORD dwThreadID = 0;
CSerCtrl.WriteToLog("ServiceMain开始!",sizeof("ServiceMain开始!"));
//DebugBreak();
//初始化
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwServiceType = SERVICE_WIN32;
hStatus = RegisterServiceCtrlHandler(tzServiceName,(LPHANDLER_FUNCTION)ServiceCtrlHandle);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
CSerCtrl.WriteToLog("RegisterServiceCtrlHandler启动失败!",sizeof("RegisterServiceCtrlHandler启动失败!"));
return;
}
CSerCtrl.WriteToLog("RegisterServiceCtrlHandler成功!",sizeof("RegisterServiceCtrlHandler成功!"));
//报告正在启动
SetServiceStatus(hStatus,&ServiceStatus);
CSerCtrl.WriteToLog("SetServiceStatus成功!",sizeof("SetServiceStatus成功!"));
//创建一个事件进行同步
hEventEnd = CreateEvent(NULL,TRUE,FALSE,NULL);
if (hEventEnd == NULL)
{
CSerCtrl.WriteToLog("CreateEvent失败!",sizeof("CreateEvent失败!"));
return;
}
ResetEvent(hEventEnd);
CSerCtrl.WriteToLog("CreateEvent成功!",sizeof("CreateEvent成功!"));
//报告启动完毕
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus,&ServiceStatus);
//暂停30秒,在这一句代码的后面下断点。
//在这段时间中,使用VC或者VS打开“附加到进程”,找到这个程序“StartTimeService.exe”,确定附加。
//时间到了,就中断了。
//如果不调试,请注释掉暂停代码。
//Sleep(30000);
//创建运行线程
hThread = CreateThread(NULL,0,ThreadMain,NULL,NULL,&dwThreadID);
if (!hThread)
{
SetEvent(hEventEnd);
}
CloseHandle(hThread);
CSerCtrl.WriteToLog("CreateThread成功!",sizeof("CreateThread成功!"));
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus,&ServiceStatus);
//等待事件退出
CSerCtrl.WriteToLog("WaitForSingleObject开始!",sizeof("WaitForSingleObject开始!"));
WaitForSingleObject(hEventEnd,INFINITE);
CSerCtrl.WriteToLog("WaitForSingleObject结束!",sizeof("WaitForSingleObject结束!"));
CSerCtrl.WriteToLog("ExitThread结束!",sizeof("ExitThread结束!"));
CloseHandle(hEventEnd);
//报告停止状态
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
SetServiceStatus(hStatus,&ServiceStatus);
CSerCtrl.WriteToLog("ServiceMain结束!",sizeof("ServiceMain结束!"));
}
void WINAPI ServiceCtrlHandle(DWORD dwOpcode)
{
switch (dwOpcode)
{
case SERVICE_CONTROL_STOP:
//开始停止
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(hStatus,&ServiceStatus);
CSerCtrl.WriteToLog("SERVICE_STOP_PENDING结束!",sizeof("SERVICE_STOP_PENDING结束!"));
//设置信号
SetEvent(hEventEnd);
CSerCtrl.WriteToLog("SetEvent结束!",sizeof("SetEvent结束!"));
//停止
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hStatus,&ServiceStatus);
CSerCtrl.WriteToLog("SERVICE_STOPPED结束!",sizeof("SERVICE_STOPPED结束!"));
break;
case SERVICE_CONTROL_PAUSE:
ServiceStatus.dwCurrentState = SERVICE_PAUSE_PENDING;
SetServiceStatus(hStatus,&ServiceStatus);
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
SetServiceStatus(hStatus,&ServiceStatus);
break;
case SERVICE_CONTROL_CONTINUE:
ServiceStatus.dwCurrentState = SERVICE_CONTINUE_PENDING;
SetServiceStatus(hStatus,&ServiceStatus);
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus,&ServiceStatus);
break;
case SERVICE_CONTROL_INTERROGATE: //检索更新状态的时
break;
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(hStatus,&ServiceStatus);
//设置信号
SetEvent(hEventEnd);
CSerCtrl.WriteToLog("SERVICE_CONTROL_SHUTDOWN结束!",sizeof("SERVICE_CONTROL_SHUTDOWN结束!"));
break;
default:
ServiceStatus.dwCurrentState = dwOpcode;
SetServiceStatus(hStatus,&ServiceStatus);
break;
}
}
DWORD WINAPI ThreadMain(LPVOID pParam)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwWrittenLen = 0;
TCHAR tzPathName[MAX_PATH] = {0};
SYSTEMTIME SystemTime = {0};
char szTime[50] = {0};
GetModuleFileName(NULL,tzPathName,MAX_PATH);
PathRemoveFileSpec(tzPathName);
PathCombine(tzPathName,tzPathName,_T("StartTime.txt"));
hFile = CreateFile(tzPathName,GENERIC_ALL,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
CSerCtrl.WriteToLog("CreateFile失败!",sizeof("CreateFile失败!"));
goto EXIT0;
}
CSerCtrl.WriteToLog("CreateFile结束!",sizeof("CreateFile结束!"));
SetFilePointer(hFile,0,NULL,FILE_END);
GetSystemTime(&SystemTime);
sprintf_s(szTime,50,"启动时间:d-d-d d:d:d----",SystemTime.wYear,SystemTime.wMonth,SystemTime.wDay,
SystemTime.wHour + 8,SystemTime.wMinute,SystemTime.wSecond);
WriteFile(hFile,szTime,(DWORD)strlen(szTime),&dwWrittenLen,NULL);
WriteFile(hFile,"\r\n",2,&dwWrittenLen,NULL);
EXIT0:
CloseHandle(hFile);
//自己在测试命令行的“start”和“stop”命令时,可以注释下面的一行,这样主线程就不会退出了。
//SetEvent(hEventEnd);
CSerCtrl.WriteToLog("ThreadMain结束!",sizeof("ThreadMain结束!"));
//Sleep(5000);
return 0;
}