现在的位置: 首页 > 综合 > 正文

Service的几个注意点和示例代码

2013年02月27日 ⁄ 综合 ⁄ 共 11045字 ⁄ 字号 评论关闭

如何编写NT ServiceMSDN->Platform SDK->DLLs, Processes, and Threads->Service中说得很清楚了,在这里我就不多说了,这里我就只说一些我个人认为的在编写service过程中要注意的地方。

 

0、在我们通过控制面板或NET START命令启动一个service时, Service Control Manager (SCM)从注册表里拿到service的可执行程序名,然后运行这个程序,从程序的入口main方法里得到serviceservice_main方法,然后就进入service_main运行。

一个service程序包含最少包含三个部分,一个是main方法,通常的工作是设置service_main方法和处理命令行参数(例如根据不同的参数执行其他的动作,象安装卸载service,手动启动停止service等等);一个是service_main方法,service程序具体要做的工作就写在这个方法里;一个是ServiceCtrlHandler方法,这个方法在service_main里设置,用来处理由SCM发给service的消息,例如service停止,暂停,系统关机等等。

 

1、手动启动一个service的方法是在servicemain方法里调用StartServiceStartService根据serviceSERVICE_TABLE_ENTRY将程序转入相应的service_main启动service时所要作的工作是写在service_main里的。通常的模式是在进入service_main后设状态为SERVICE_START_PENDING,然后进行一些初始化动作,然后执行一个线程或进程,在其中进行service的工作,然后设状态为SERVICE_RUNNING。一定要注意的是,启动service后,必须保证在两分钟内service的状态就会被设成SERVICE_RUNNING,否则会报错。

 

2、停止一个service的方法是在servicemain方法里调用ControlService(hService,SERVICE_CONTROL_STOP,&ServStat)发送SERVICE_CONTROL_STOP消息到Service Control Manager (SCM)SCM收到这个消息后就会通知service,执行ServiceCtrlHandlercase SERVICE_CONTROL_STOP:内的工作。结束动作通常也不能太久,因为在关机时,系统会给每个service大概20秒时间清场(这个时间可以在注册表中设置)

 

3、安装和卸载一个service的方法是在servicemain方法里调用CreateService方法和DeleteService方法,卸载方法前先要判断service是否在运行,如果在运行要先将服务停止

否则无法删除。

 

4设置service状态的方法是调用SetServiceStatus,在写service的启动和停止动作是要设置其状态,分别在上面提到的service_mainServiceCtrlHandler里。查询service状态的方法QueryServiceStatus,在停止服务时,ControlService方法只是发送了一个消息后就立即返回了,因此通常要在执行完ControlService后,利用whilesleepQueryServiceStatus来不断查询service的状态,直到状态为SERVICE_STOPPEDStartServiceControlService不同,并不是立即返回的,它会直到service_main内的代码执行完后才返回。

 

5service_main即使返回,service的程序进程也不会退出,直到service状态为SERVICE_STOPPED时,才会终止并退出。

 

6、在设置service状态时,通过指定dwWin32ExitCodedwServiceSpecificExitCode可以设定当service在此状态下出错时的弹出式Message。不过只能设定一个错误代码。

 

7、使用ChangeServiceConfig2添加修改service的描述。

 

8、默认情况下service程序是不能与桌面交互的,即不能打开窗口。通过ChangeServiceConfig函数设定SERVICE_INTERACTIVE_PROCESS属性,或通过控制面板选中"允许服务与桌面交互",则服务程序可以打开窗口。例如在服务中使用CreateProcess创建了一个进程,只要在STARTUPINFOwShowWindowdwFlags设定了SW_SHOWSTARTF_USESHOWWINDOW,则进程就会在打开的一个新窗口中运行。

 

9、不论是否设定SERVICE_INTERACTIVE_PROCESS,在service中都可以通过MessageBox方法弹出MessageBox。这个函数的第一个参数指定为NULL,表示不指定父窗口。在第四个参数中指定MB_DEFAULT_DESKTOP_ONLYMB_SERVICE_NOTIFICATION表示以桌面为父窗口。

 

10.如果要停止的一个Service上有其他正在运行的服务依赖着,这时直接停止这个服务就会出错,因此如果需要停止的服务有可能被其他服务所依赖,在停止前必须用EnumDependentServices()方法取得所有依赖于这个服务的服务,将这些服务依次停止后才行。具体代码示例请看MSDN->HOWTO->ID:Q245230

 

11、启动service时可以使用启动参数,在定义service_main方法时其两个参数(DWORD argc, LPTSTR *argv),第一个即为参数个数,第二个则是一个参数数组指针。如何传入参数呢,由于service_main并不是程序入口,因此参数是通过main从命令行传至StartService方法,而调用StartService时,StartService的第二第三个参数,就是传入service_main的参数。如果serviceauto-started的,每次开机时就会自动启动,没有给我们手工通过命令行传入参数的机会,这时我们只有在安装service的时候,就把参数传入。在CreateService时,将CreateServicelpBinaryPathName值设成例如SimpleService.exe arg1 arg2的样子,这样每当SCM启动serviceSCM就会从main方法中获得参数并将其传入这个serviceservice_main中。

 

12.在启动一个service之后,在service的状态是已启动(SERVICE_RUNNING)”之前,这段时间内,是无法启动另一个service的。

 

例子代码:

#include #include #include #include #include #include #include

#define SERVICE_NAME "TSService"#define SERVICE_DISPNAME "vPBX PathFinder TSService"#define SERVICE_DESCRIPTIONNAME "Start vPBX PathFinder service"#define SERVICE_EXENAME "/ServiceFrame.exe"#define LOG_FILENAME "/Service.log"#define START_EXENAME "/vpbxw.exe"#define STOP_EXENAME "/StopServer.exe"#define CMD_EXENAME " -svc"#define REG_ITEM "SOFTWARE/VisionNex/vPBX_Server"#define REG_KEY "home"#define FLAG_FILENAME "/PortKeeper.svc"#define START_DELAY 10000#define STOP_DELAY 2000#define COUNT_DELAY 50#define TIME_DELAY 2000

SERVICE_STATUS m_ServiceStatus;SERVICE_STATUS_HANDLE m_ServiceStatusHandle;BOOL bRunning=false;char Path[256];

void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);void WINAPI ServiceCtrlHandler(DWORD Opcode);

BOOL InstallService(int flag);BOOL DeleteService();BOOL StartupService();BOOL StopService();BOOL ChangeService();

BOOL EndService();BOOL QueryReg ();DWORD GetStatus(SC_HANDLE service);void LogService(char* error);BOOL TestTs(int sleep, int count, int sec);BOOL WaitTsStartup(int sleep, int count, int sec);

 

int main(int argc, char* argv[]){  if(!QueryReg()) return 1;  if(argc>1) {  if(strcmp(argv[1],"-i")==0) {   InstallService(0);  }    else if (strcmp(argv[1],"-id")==0){      InstallService(1);    }  else if(strcmp(argv[1],"-d")==0) {   DeleteService();  }    else if(strcmp(argv[1],"-r")==0) {   StartupService();  }    else if(strcmp(argv[1],"-s")==0) {   StopService();  }    else if(strcmp(argv[1],"-c")==0) {      ChangeService();    }    else if(strcmp(argv[1],"-v")==0) {   printf("serivce frame version:1.0.0.5: debug=pipe(limit -0.3)");  }  else {   printf("Unknown Switch Usage For install use -i, for uninstall use -d, for run use -r, for stop use -s ");  } } else {  SERVICE_TABLE_ENTRY DispatchTable[]={{SERVICE_NAME, ServiceMain},{NULL,NULL}};    StartServiceCtrlDispatcher(DispatchTable);  } return 0;}

void WINAPI ServiceMain(DWORD argc, LPTSTR *argv){  DWORD status;   DWORD specificError;   LogService("Service Startup...");  m_ServiceStatus.dwServiceType        = SERVICE_WIN32;   m_ServiceStatus.dwCurrentState       = SERVICE_START_PENDING;   m_ServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;   m_ServiceStatus.dwWin32ExitCode      = 0;   m_ServiceStatus.dwServiceSpecificExitCode = 0;   m_ServiceStatus.dwCheckPoint         = 0;   m_ServiceStatus.dwWaitHint           = 0;   m_ServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);    if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {       LogService("Error: RegisterServiceCtrlHandler");      return;   }     /*  //create pipe  SECURITY_ATTRIBUTES sa; HANDLE hRead,hWrite; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE;/* if (!CreatePipe(&hRead,&hWrite,&sa,0)) {   LogService("Error On CreatePipe()"); }   //---------  hWrite = CreateFile("d:/process.log",GENERIC_WRITE, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);  */

  PROCESS_INFORMATION pinfo;  STARTUPINFO sinfo;   ZeroMemory(&sinfo, sizeof(sinfo));  sinfo.cb = sizeof(sinfo);  char strDir[256];  char strDir_stop[256];  strcpy(strDir,Path);  strcpy(strDir_stop,Path);  strcat(strDir,START_EXENAME);  strcat(strDir_stop,STOP_EXENAME);  LPCTSTR lpszBinaryPathName=strDir;    LPCTSTR lpszBinaryPathName_stop=strDir_stop; 

  LogService("Start Create StopServer process");  if(!CreateProcess(lpszBinaryPathName_stop, CMD_EXENAME, NULL,NULL,FALSE,0,NULL,Path,&sinfo,&pinfo)) {    LogService("Error: CreateProcess:stop befor start");  return;  }  Sleep(STOP_DELAY);

  ZeroMemory(&sinfo, sizeof(sinfo));  sinfo.cb = sizeof(sinfo);  //Set Process output  //sinfo.hStdError = hWrite; //sinfo.hStdOutput = hWrite; sinfo.wShowWindow = SW_SHOW;  sinfo.dwFlags = STARTF_USESHOWWINDOW ;//| STARTF_USESTDHANDLES;  LogService("Start Create vPBXW process");  if(!CreateProcess(lpszBinaryPathName, CMD_EXENAME, NULL,NULL,TRUE,0,NULL,Path,&sinfo,&pinfo)) {    LogService("Error: CreateProcess:start");    m_ServiceStatus.dwCurrentState       = SERVICE_STOPPED;     m_ServiceStatus.dwCheckPoint         = 0;     m_ServiceStatus.dwWaitHint           = 0;     m_ServiceStatus.dwWin32ExitCode      = ERROR_SERVICE_SPECIFIC_ERROR;     m_ServiceStatus.dwServiceSpecificExitCode = 0;     SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus);     return;  }    //CloseHandle(hWrite);  LogService("Created vPBXW process");  //read pipe    /*        char buffer[4096] = {0};      DWORD bytesRead = 0;      int i =1;      while (3)       {        i = i -1;        BOOL ret = ReadFile(hRead,buffer,4095,&bytesRead,NULL);        if (ret == NULL){          LogService("Read return NULL");          break;        }        if(ret == 0){          LogService("Read return 0");          break;        }        if(bytesRead == 0){          LogService("Read size 0");        }        else{          LogService("Read Success");          buffer[bytesRead]=0;          LogService(buffer);        }      }     //-----*/

  if(!TestTs(START_DELAY,COUNT_DELAY,TIME_DELAY)){    CloseHandle(pinfo.hThread);    CloseHandle(pinfo.hProcess); // CloseHandle(hRead);    return;  }

  m_ServiceStatus.dwCurrentState       = SERVICE_RUNNING;   m_ServiceStatus.dwCheckPoint         = 0;   m_ServiceStatus.dwWaitHint           = 0;    if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus)) {       LogService("Error: SetServiceStatus:SERVICE_RUNNING");      return;   }

  CloseHandle(pinfo.hThread);  CloseHandle(pinfo.hProcess);//CloseHandle(hRead);  return; }

BOOL EndService(){  PROCESS_INFORMATION pinfo;  STARTUPINFO sinfo;   ZeroMemory(&sinfo, sizeof(sinfo));  sinfo.cb = sizeof(sinfo);   char strDir[256];  strcpy(strDir,Path);  strcat(strDir,STOP_EXENAME);  LPCTSTR lpszBinaryPathName=strDir;      if(!CreateProcess(lpszBinaryPathName, CMD_EXENAME, NULL,NULL,FALSE,0,NULL,Path,&sinfo,&pinfo)) {    LogService("Error: CreateProcess:stop");  return false;  }   LogService("Service Stop...");  LogService("Service Stop OK");  CloseHandle(pinfo.hThread);  CloseHandle(pinfo.hProcess); return true;}

void WINAPI ServiceCtrlHandler(DWORD Opcode){    switch(Opcode)     {          case SERVICE_CONTROL_STOP:            m_ServiceStatus.dwWin32ExitCode = 0;             m_ServiceStatus.dwCurrentState  = SERVICE_STOPPED;             m_ServiceStatus.dwCheckPoint    = 0;             m_ServiceStatus.dwWaitHint      = 0;             SetServiceStatus (m_ServiceStatusHandle,&m_ServiceStatus);          bRunning=false;            EndService();         break;                case SERVICE_CONTROL_SHUTDOWN:             bRunning=false;            EndService();            char strDir[256];            strcpy(strDir,Path);            strcat(strDir,FLAG_FILENAME);            remove(strDir);            break;         case SERVICE_CONTROL_INTERROGATE:             break;     }      return; }

BOOL InstallService(int flag){ HANDLE schSCManager,schService;

 schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);   if (schSCManager == NULL) {  printf("Error Installing Service ");    LogService("Error: Installing Service:OpenSCManager");  return false;  }

  char strDir[256];  strcpy(strDir,Path);  strcat(strDir,SERVICE_EXENAME);  LPCTSTR lpszBinaryPathName=strDir;      schService = CreateService(schSCManager,                             SERVICE_NAME,                              SERVICE_DISPNAME,                             SERVICE_ALL_ACCESS,        // desired access                              SERVICE_WIN32_OWN_PROCESS, // service type                              SERVICE_AUTO_START,        // start type                              SERVICE_ERROR_NORMAL,      // error control type                              lpszBinaryPathName,        // service's binary                              NULL,                      // no load ordering group                              NULL,                      // no tag identifier                              NULL,                      // no dependencies                              NULL,                      // LocalSystem account                              NULL);                     // no password

  if (schService == NULL) {  printf("Error Installing Service ");    LogService("Error: Installing Service:CreateService");   CloseServiceHandle(schSCManager);    return false;    }  printf("Service Installed OK ");  LogService("Service Installed OK");

  if(flag == 1){    ChangeServiceConfig(schService,SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, NULL, NULL,NULL,NULL,NULL,NULL,NULL);  }

  char description[] = SERVICE_DESCRIPTIONNAME;  SERVICE_DESCRIPTION svrDescription;  svrDescription.lpDescription = description;  ChangeServiceConfig2(schService,SERVICE_CONFIG_DESCRIPTION,&svrDescr

抱歉!评论已关闭.