最新文章
热门文章
WinPE操作系统的使用及简介(破解 
QQ象棋,联众象棋游戏如何作弊 
如何解决网页中图片大小类型等属 
总结几种结构体初始化方法 
关于硕士毕业论文自动生成目录和 
VC建立类向导(class wizard)错误 
C++中取随机数函数rand和srand用 
VC编写自己构造http协议数据的po 
如何查看得到windows系统管理员帐 
由DCOM权限引起的在windows2003上 
当前位置:李露的博客 >> 电脑技术 >> 浏览文章
VS2005写的一个Windows服务控制类+测试程序(1)
更新日期:2010年04月09日  来源:本站原创  作者:天漏客   访问次数:次  【字体:

可以使用命令行方式进行安装、启动、停止、卸载,命令参数分别为:install、start、stop、uninstall,参数不区分大小写,可以加反斜杠“/”,也可以不加。

这个服务程序的功能是:服务测试程序。随机启动,启动时会将当前时间写入StartTime.txt文件,并将运行日志写入log文件夹。看参考服务描述。

程序运行很快,一般启动后就退出了,除非注释掉SetEvent功能。

整个工程源码下载:VS2005写的一个Windows服务控制类+测试程序 [点击浏览该文件: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结束!"));

…………………………

VS2005写的一个Windows服务控制类+测试程序


源码有三个主要文件: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;
}

发表评论】【告诉好友】【打印此文】【收藏此文】【关闭窗口
上一篇:使用VC或VS对Windows服务进行源码级调试小技巧 下一篇:echoware做中转连接的使用小结与实例(1)

Copyright 2006-2012 Powered by LiLu.NAME,李露的博客 All Rights Reserved.
E-Mail:lilu.name#gamil.com(注意是gmail,自己改) QQ:285252760
苏ICP备08016526号