c - 如何正确使用SetServiceStatus告诉Windows我的服务正在停止?

标签 c windows-services

对示例的长度感到抱歉,但为了获得服务所需的所有组件,它必须这么长。

在其他人的帮助下,我成功地获得了一个可以干净启动的服务,但现在它不会干净地停止。

第一次尝试快速停止它时会出现错误

Could not stop the My service service on local computer
The service did not return an error. This could be an internal Windows error or an internal service error
If the problem persists, contact your system administrator

即使在 sleep 循环经过 5 分钟后,服务仍会继续运行。

第二次尝试停止时,任务管理器显示进程立即停止,但服务管理器花了很长时间才给出错误

Could not stop the My service service on local computer
Error 1053: The service did not respond to the start or control request in a timely fashion.

这是源代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <windows.h>
#include <winsvc.h>
#include <time.h>

#define MY_SVC_NAME "My service"
#define THE_PROG "\"C:\\Program Files\\My software\\bin\\The Prog.exe\""
#define SLEEP_TIME 300000

SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;

void WINAPI ServiceMain(DWORD argc, LPSTR argv);
void WINAPI ControlHandler(DWORD request);
void InitService();


int cont_running = 1;

DWORD WINAPI ServiceHandlerProc(DWORD ControlCode, DWORD a, void *b, void *c)
{
  switch (ControlCode) {
  case SERVICE_CONTROL_STOP :
    cont_running = 0;
    ServiceStatus.dwCheckPoint=0;
    ServiceStatus.dwWin32ExitCode = 0;
    ServiceStatus.dwCurrentState  = SERVICE_STOP_PENDING;
    ServiceStatus.dwWaitHint =2000;
    SetServiceStatus (hStatus, &ServiceStatus);
    Sleep(1000);
    ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
    SetServiceStatus (hStatus, &ServiceStatus);
    break;
  case SERVICE_CONTROL_SHUTDOWN :
    cont_running = 0;
    ServiceStatus.dwCheckPoint=0;
    ServiceStatus.dwWin32ExitCode = 0;
    ServiceStatus.dwCurrentState  = SERVICE_STOP_PENDING;
    ServiceStatus.dwWaitHint =2000;
    SetServiceStatus (hStatus, &ServiceStatus);
    Sleep(1000);
    ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
    SetServiceStatus (hStatus, &ServiceStatus);
    break;
  }

  return 0;

}

void WINAPI ServiceMain(DWORD argc, LPSTR argv)
{
  int hServiceStatus;

  ServiceStatus.dwServiceType        = SERVICE_WIN32;
  ServiceStatus.dwCurrentState       = SERVICE_START_PENDING;
  ServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  ServiceStatus.dwWin32ExitCode      = 0;
  ServiceStatus.dwServiceSpecificExitCode = 0;
  ServiceStatus.dwCheckPoint         = 0;
  ServiceStatus.dwWaitHint           = 0;

  hServiceStatus = RegisterServiceCtrlHandlerEx(MY_SVC_NAME, ServiceHandlerProc,0);
  /*
  if (hStatus == (SERVICE_STATUS_HANDLE)0) {
    return;
  }
  */

  Sleep(1000);

  ServiceStatus.dwCheckPoint=0;
  ServiceStatus.dwWaitHint=0;
  ServiceStatus.dwCurrentState=SERVICE_RUNNING;
  SetServiceStatus( hServiceStatus, &ServiceStatus);

  InitService();

  return;
}

void InitService()
{
  cont_running=1;
  do {
    system(THE_PROG);
    Sleep(SLEEP_TIME);
  } while (cont_running);
}

int main(int argc, char *argv[], char *envp[])
{
  SERVICE_TABLE_ENTRY ServiceStartTable[2];
  ServiceStartTable[0].lpServiceName = MY_SVC_NAME;
  ServiceStartTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
  ServiceStartTable[1].lpServiceName = NULL;
  ServiceStartTable[1].lpServiceProc = NULL;


  if (!StartServiceCtrlDispatcher(ServiceStartTable))
  {
    DWORD err = GetLastError();
    if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
      return 1;
  }

  return 0;
}

我引用了以下文档没有成功 http://msdn.microsoft.com/en-us/library/ms809975.aspx LUA服务引用手册

最佳答案

问题似乎出在您的 SERVICE_STATUS_HANDLE hStatus 全局变量上:它没有在程序中的任何位置分配,但使用了很多次。

此外,局部变量 int hServiceStatus 根本没有任何意义。

解决方案:删除 hServiceStatus 局部变量,并将每次使用 hServiceStatus 替换为正确的 hStatus 变量。

提示:也许您已经意识到这一点,但您应该在收到控制命令时设置 STOP_PENDING 状态,并仅在真正停止工作线程时设置 STOPPED。

关于c - 如何正确使用SetServiceStatus告诉Windows我的服务正在停止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8972416/

相关文章:

c - 为什么我的可执行文件中的入口点地址是0x8048330? (0x330 是 .text 部分的偏移量)

c - 使用C语言在自定义shell中进行箭头键控制

windows - 需要关于用不可见的 WinForm 应用程序替换 Windows 服务的建议

c#授予Windows用户 "Log On As Service"权限

JavaExe 和 Java 应用程序作为 Windows 系统服务与桌面交互

使用 sprintf() 函数后 C 字符字符串不可读

每当使用除法时,C 程序中的计算结果总是为 0

c - 打印给定月份和年份的月历

c - 使用winsvc.h中的SERVICE_TABLE_ENTRY避免编译器警告的正确类型转换是什么

c# - 向 Windows 服务发送 Windows 消息