// ServiceTest.cpp : Defines the entry point for the console application.
 // #include "stdafx.h"
 #include <winsvc.h>
 #ifdef _DEBUG
 #define new DEBUG_NEW
 #undef THIS_FILE
 static char THIS_FILE[] = __FILE__;
 #endif
 CWinApp theApp;
 using namespace std;
 //***********************************************************************************//
 //变量声明
 //***********************************************************************************//
 //服务内部名
 #define APPNAME "DBDataBackup"
 //服务显示名
 #define SZSERVICENAME _T("数据库定时清理服务")
 //服务状态
 SERVICE_STATUS ssStatus;
 //服务句柄
 SERVICE_STATUS_HANDLE sshStatusHandle;
 //SC句柄
 SC_HANDLE schSCManager;
 SC_HANDLE schService;
 LPCTSTR * lpServiceArgVectors;
 //服务调试标志
 BOOL bDebug=FALSE;
 //互斥信号量
 CRITICAL_SECTION errCritical;
 //服务退出事件
 HANDLE hSysExitEvent = NULL;
 //***********************************************************************************//
 //函数声明
 //服务入口函数
 void  WINAPI  Service_Main(DWORD dwArgc, LPTSTR *lpszArgv);
 //服务控制处理函数
 void WINAPI Service_Ctrl(DWORD dwCtrlCode);
 //标准错误输出函数
 void StdErrorHandler(CString errorMessage);
 //服务安装处理函数
 void installService();
 //服务卸载处理函数
 void removeService();
 //服务调试处理函数
 void debugService();
 //写服务日志
 void AddToAppLog(CString errorMessage);
 //获得系统时间
 CString GetSystemTime();
 //服务启动处理函数
 void ServiceStart();
 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint);
 //服务停止处理函数
 void ServiceStop();
 //服务暂停处理函数
 void ServicePause();
 //服务继续处理函数
 void ServiceContinue(); //***********************************************************************************//
 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
 {
  //初始化信号量
  InitializeCriticalSection(&errCritical);
  //初始化MFC
  if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
  {
   cerr << _T("致命错误: MFC初始化失败") << endl;
   return -1;
  }
  else
  {
   //注册服务入口,服务名、服务入口函数
   //Windows执行服务入口在Service_Main
   SERVICE_TABLE_ENTRY dispatchTable[2]={
    {SZSERVICENAME,Service_Main},    
    { NULL,NULL}};
   //获得当前可执行文件目录和文件名
   char exeFullPath[MAX_PATH];
   GetModuleFileName(NULL,exeFullPath,MAX_PATH);
   for(int i=strlen(exeFullPath); i>=0; i--)
   {
    if(exeFullPath[i]=='//')
    {
     exeFullPath[i]=0;
     break;
    }
   }
   //设置当前进程的当前路径为服务的路径
   SetCurrentDirectory(exeFullPath); 
   //处理命令行参数
   if(argc>1&&*argv[1]=='-')
   {
    //参数为-install,安装服务
    if(_stricmp("install",argv[1]+1)==0)
    {
     //执行安装服务
     installService();
    }
    //参数为-remove,卸载服务
    else if(_stricmp("remove",argv[1]+1)==0)
    {
     //执行卸载服务
     removeService();
    }
    //参数为-debug,调试服务
    else if(_stricmp("debug",argv[1]+1)==0)
    {
     //置服务调试标志
     bDebug=TRUE;
     //执行调试服务
     debugService();
    }
    else
    {
     //参数格式不合法
     printf("输入 %s - install 来安装服务 /n",APPNAME);
     printf("输入 %s - remove 来卸载服务 /n",APPNAME);
     printf("输入 %s - debug 来调试服务 /n",APPNAME);
    }
    exit(0);
   }
   //如果未能和上面的如何参数匹配,则可能是服务控制管理程序来启动该程序。
   CString errmessage;
   printf("/n已调用StartServiceCtrlDispatcher./n");
   printf("这可能需要几秒钟,请等待./n");
   //立即调用StartServiceCtrlDispatcher函数。
   if(!StartServiceCtrlDispatcher(dispatchTable))
   {
    StdErrorHandler("调用StartServiceCtrlDispatcher失败.");
    AddToAppLog(errmessage);
   }
   else
   {
    StdErrorHandler("调用StartServiceCtrlDispatcher成功.");
    AddToAppLog(errmessage);
   }
  }
  return 0;
 } //******************************************************//
 //服务入口函数
 //******************************************************//
 void  WINAPI  Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
 {
  //注册服务控制处理函数,服务APPNAME,控制函数Service_Ctrl
  sshStatusHandle=RegisterServiceCtrlHandler(APPNAME,Service_Ctrl);
  //如果注册失败
  if(!sshStatusHandle)
  {
   CString err;
   err="服务注册失败";
   StdErrorHandler(err);
   goto cleanup;
   return;
  }
  //初始化 SERVICE_STATUS 结构中的成员
  ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
  ssStatus.dwServiceSpecificExitCode=0;
  //更新服务状态为正在启动SERVICE_START_PENDING
  if(!ReportStatusToSCMgr(
   SERVICE_START_PENDING, //服务状态,The service is starting.
   NO_ERROR,    //退出码         
   3000))     //等待时间
  {
   goto cleanup;   //更新服务状态失败则转向 cleanup
  }
  //服务启动主函数
  ServiceStart();
  return; cleanup:
  //把服务状态更新为 SERVICE_STOPPED,并退出。
  if(sshStatusHandle)
  {
   ReportStatusToSCMgr(SERVICE_STOPPED,GetLastError(),0);
  }
 }  
 //******************************************************//
 //服务控制处理函数
 //******************************************************//
 void WINAPI Service_Ctrl(DWORD dwCtrlCode)
 {
  //处理控制请求码
  switch(dwCtrlCode)
  {
  //先更新服务状态为 SERVICDE_STOP_PENDING,再停止服务。
  case SERVICE_CONTROL_STOP:
   {
    ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);
    ServiceStop();     //由具体的服务程序实现
    ssStatus.dwCurrentState=SERVICE_STOPPED;
    break;
   }
  //暂停服务
  case SERVICE_CONTROL_PAUSE:
   {
    ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);
    ServicePause();    //由具体的服务程序实现
    ssStatus.dwCurrentState=SERVICE_PAUSED;
    break;
   }
  //继续服务
  case SERVICE_CONTROL_CONTINUE:
   {
    ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);
    ServiceContinue(); //由具体的服务程序实现
    ssStatus.dwCurrentState=SERVICE_RUNNING;
    break;
   }
  //更新服务状态
  case SERVICE_CONTROL_INTERROGATE:
   {
    break;
   }
  //无效控制码
  default:
   {
    break;
   }
     }
  //当前服务状态
  ReportStatusToSCMgr(ssStatus.dwCurrentState,NO_ERROR,0);
 } //******************************************************//
 //服务安装处理函数
 //******************************************************//
 void installService()
 {
  SC_HANDLE   schService;
     SC_HANDLE   schSCManager;
  TCHAR szPath[512];
  CString err;
  //得到程序磁盘文件的路径
  if(GetModuleFileName(NULL,szPath,512)==0)
  {
   err.Format("不能安装 %s - %s /n",TEXT(APPNAME),GetLastError());
   StdErrorHandler(err);
   return;
  }
  //打开服务管理数据库
  schSCManager=OpenSCManager(
   NULL,       //本地计算机
   NULL,       //默认的数据库
   SC_MANAGER_ALL_ACCESS   //要求所有的访问权
   );
  if(schSCManager)
  {
   //登记服务程序
   schService=CreateService(
    schSCManager,    //服务管理数据库句柄
    TEXT(APPNAME),    //服务名
    TEXT(SZSERVICENAME),  //用于显示服务的标识
    SERVICE_ALL_ACCESS,   //响应所有的访问请求
    SERVICE_WIN32_OWN_PROCESS, //服务类型
    SERVICE_AUTO_START,   //启动类型
    SERVICE_ERROR_NORMAL,  //错误控制类型
    szPath,      //服务程序磁盘文件的路径
    NULL,      //服务不属于任何组
    NULL,      //没有tag标识符
    NULL,      //启动服务所依赖的服务或服务组,这里仅仅是一个空字符串
    NULL,      //LocalSystem 帐号
    NULL);
   if(schService)
   {
    err.Format("%s 已安装.",TEXT(APPNAME));
    StdErrorHandler(err);
    CloseServiceHandle(schService);
   }
   else
   {
    err.Format("创建服务失败,服务可能已经安装");
    StdErrorHandler(err);
   }
   CloseServiceHandle(schSCManager);
  }
  else
  {
   err.Format("打开SCManager失败");
   StdErrorHandler(err);
  }
  CloseServiceHandle(schSCManager);
  return;
 } //******************************************************//
 //服务卸载处理函数
 //******************************************************//
 void removeService()
 {
  SC_HANDLE schService;
  SC_HANDLE schSCManager;
  CString err;
  //打开服务管理数据库
  schSCManager=OpenSCManager(
   NULL,    //本地计算机
   NULL,    //默认的数据库
   SC_MANAGER_ALL_ACCESS  //要求所有的访问权
   );
  if(schSCManager)
  {
   //获取服务程序句柄
   schService=OpenService(
    schSCManager,   //服务管理数据库句柄
    TEXT(APPNAME),   //服务名
    SERVICE_ALL_ACCESS  //响应所有的访问请求
    );
   if(schService)
   {
    //试图停止服务
    if(ControlService(
     schService,            //服务程序句柄
     SERVICE_CONTROL_STOP,  //停止服务请求码
     &ssStatus              //接收最后的服务状态信息
     ))
    {
     err.Format("停止 %s 中",TEXT(APPNAME));
     StdErrorHandler(err);
     Sleep(1000);
     //等待服务停止
     while(QueryServiceStatus(schService,&ssStatus))
     {
      if(SERVICE_STOP_PENDING==ssStatus.dwCurrentState)
      {
       cout<<".";
       Sleep(1000);
      }
      else
      {
       break;
      }
     }
     if(SERVICE_STOPPED==ssStatus.dwCurrentState)
     {
      err.Format("/n %s 已被停止. /n",TEXT(APPNAME));
      StdErrorHandler(err);
     }
     else
     {
      err.Format("/n %s 试图停止失败. /n",TEXT(APPNAME));
      StdErrorHandler(err);
     }
    }
    //删除已安装的服务程序安装
    if(DeleteService(schService))
    {
     err.Format("%s 已经被卸载. /n",TEXT(APPNAME));
     StdErrorHandler(err);
    }
    else
    {
     err.Format("删除服务失败");
     StdErrorHandler(err);
    }
    CloseServiceHandle(schService);
   }
   else
   {
    err.Format("连接服务失败,不存在此服务");
    StdErrorHandler(err);
   }
   CloseServiceHandle(schSCManager);
  }
  else
  {
   err.Format("打开SCManager失败");
   StdErrorHandler(err);
  }
 }  
 //******************************************************//
 //服务启动处理函数
 //******************************************************//
 void ServiceStart()
 {
  //默认监测周期是3分钟
  int nWaitTime=3000;
  // 向SCM报告目前的状态
  ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 20000);  if(!(hSysExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL))){
   StdErrorHandler("服务退出事件创建失败");
   return;
  }
  // 向SCM报告当前进度,运行状态
  ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
  StdErrorHandler("服务已启动");
  long int times=20;
  while(times)
  { 
   times--;
   cout<<times<<",";
   // 等待停止标志
   if(WaitForSingleObject(hSysExitEvent, nWaitTime) == WAIT_OBJECT_0)
   {   
    // 通知SCM服务正在结束
    ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 10000);
    StdErrorHandler("数据库定时清理服务正在终止...");
    return;
   }
   Beep(1000,200);
   Sleep(nWaitTime);
  }
 }
 //******************************************************//
 //服务停止处理函数
 //******************************************************//
 void ServiceStop()
 {
  SetEvent(hSysExitEvent);
 } //******************************************************//
 //服务暂停处理函数
 //******************************************************//
 void ServicePause()
 {} //******************************************************//
 //服务继续处理函数
 //******************************************************//
 void ServiceContinue()
 {} 
 //******************************************************//
 //服务日志记录处理函数
 //******************************************************//
 void AddToAppLog(CString errorMessage)
 {
  
 }
 //******************************************************//
 //服务调试处理函数
 //******************************************************//
 void debugService()
 {
  ServiceStart();
 } //******************************************************//
 //返回当前系统时间
 //******************************************************//
 CString GetSystemTime()
 {
  SYSTEMTIME systemTime;
  CString timeString;
  GetLocalTime(&systemTime);
  timeString.Format("%04d年%02d月%02d日 %02d:%02d:%02d",
   systemTime.wYear, systemTime.wMonth, systemTime.wDay,
   systemTime.wHour, systemTime.wMinute, systemTime.wSecond,
   systemTime.wMilliseconds);
  return timeString;
 } /*******************************************************
 名称:ReportStatusToSCMgr
 参数:
  dwCurrentState:当前状态
  dwWin32ExitCode:win32退出码
  dwWaitHint: 该状态可能持续的时间
 返回值:BOOL
 功能:向Service Control Manager报告状态
 *******************************************************/
 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
        DWORD dwWin32ExitCode,
        DWORD dwWaitHint)
 {
  static DWORD dwCheckPoint = 1;
  BOOL fResult = TRUE;
  
  if(!bDebug) {
   // 如果在初始化状态,不接受任何命令
   if(dwCurrentState == SERVICE_START_PENDING)
    ssStatus.dwControlsAccepted = 0;
   else
    ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;   ssStatus.dwCurrentState = dwCurrentState;
   ssStatus.dwWin32ExitCode = dwWin32ExitCode;
   ssStatus.dwWaitHint = dwWin32ExitCode;   // 如果状态为正在运行或已经停止,则checkpoit为0
   if((dwCurrentState == SERVICE_RUNNING) ||
    (dwCurrentState == SERVICE_STOPPED)){ 
    ssStatus.dwCheckPoint = 0;
    dwCheckPoint = 1;
   }
   else 
    ssStatus.dwCheckPoint = dwCheckPoint++;   // 向服务管理器报告当前状态
   if(!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus))) {
 //   StdErrorHandler(COMMANDHANDLER, "向SCM报告状态失败", SERVICEFLAG);
   }
  }
  return fResult;
 } //******************************************************//
 //报告系统错误
 //******************************************************//
 void StdErrorHandler(CString errorMessage)
 {
  EnterCriticalSection(&errCritical);
  AddToAppLog(errorMessage);
  printf("%s:%s/n",GetSystemTime(),errorMessage);
  LeaveCriticalSection(&errCritical);
 }