windows服务的撰写方法

windows服务类似于UINX的守护进程,在后台运行的程序,在系统启动的时刻启动进程,不依赖于交互环境;服务有广泛用途,如QQ管家,360都有服务程序,用于监视程序的运行;

windows服务程序包括两个部分:服务程序(实现你想要的功能)和控制服务的程序(作用是控制服务程序,如创建服务,开始服务,停止服务等)

服务程序主函数结构如下:

int _tmain(int argc, _TCHAR* argv[])
{
    SERVICE_TABLE_ENTRY DispatchTable[] =
    {
        { SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
        { NULL, NULL }
    };

    StartServiceCtrlDispatcher( DispatchTable );
    
    return 0;
}

StartServiceCtrlDispatcher函数连接到SCM(服务控制管理器),启动控制分派线程;分派线程会陷入到一个循环当中,等待 DispatchTable[]中所有服务的控制请求;当

DispatchTable[]中的所有服务都停止后,SCM会向控制分派线程发送一个结束的请求,然后StartServiceCtrlDispatcher会返回,程序结束;

DispatchTable[]中记录的分别是服务的名称,和与其对应的服务的入口点,上述服务入口点是SvcMain,可理解为服务主程序;


服务入口点SvcMain是一个函数,撰写方法如下:
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{    
        gSvcStatusHandle = RegisterServiceCtrlHandler(         SVCNAME,         SvcCtrlHandler);   
        if( !gSvcStatusHandle )  
        {        
             return;    
        }     
        gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;   
        gSvcStatus.dwServiceSpecificExitCode = 0;       
        ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );   

        SvcInit( dwArgc, lpszArgv );
}



RegisterServiceCtrlHandler注册服务的控制函数SvcCtrlHandler,服务的停止,暂停等控制都是通过该函数向服务传递过来的;

SvcCtrlHandler的模式如下:
VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
{
  switch(dwCtrl)   
 {        
      case SERVICE_CONTROL_STOP:         
        ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);       
        SetEvent(ghSvcStopEvent);//激发一个停止服务的事件        
        ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);                  
        return;      
      case SERVICE_CONTROL_INTERROGATE:         
      break;       
      default:          break;
  }   
}

上面的函数SvcInit函数内部,是完成你想要的功能的地方,函数内容如下:

VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)
{
    ghSvcStopEvent = CreateEvent(
                         NULL,    // default security attributes
                         TRUE,    // manual reset event
                         FALSE,   // not signaled
                         NULL);   // no name

    if ( ghSvcStopEvent == NULL)
    {
        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
        return;
    }

    ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );

    while(1)
    {
       

       // SvcCtrlHandler函数内的停止事件激发,该处结束死循环,服务结束;
        WaitForSingleObject(ghSvcStopEvent, INFINITE);

    
        ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
        return;
    }
}


所有想要的工作走可以在上面while的死循环内完成;上面的函数ReportSvcStatus用于设置状态,用于通知SCM当前服务的状态,注意,在服务控制器中中必须每次都设置状态,即使状态没有改变;

上面是服务的典型写法,下面介绍一下服务控制程序的写法:服务程序写好后,需要通过API来控制其创建,开始,暂停,继续及查询等操作;创建服务:

VOID SvcCreate()
{
    SC_HANDLE schSCManager;
    SC_HANDLE schService;
    TCHAR szPath[MAX_PATH];

    if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )
    {
        printf("Cannot install service (%d)\n", GetLastError());
        return;
    }

    int len = _tcslen(szPath);
    for(int i = len - 1; i >= 0; --i)
    {
        if(szPath[i] != _T('\\'))
            szPath[i] = _T('\0');
        else
            break;
    }

    _tcscat(szPath, _T("Service_Demo.exe"));//上面撰写的服务程序

    //打开SCM
    schSCManager = OpenSCManager(
        NULL,                    // local computer
        NULL,                    // ServicesActive database
        SC_MANAGER_ALL_ACCESS);  // full access rights
 
    if (NULL == schSCManager)
    {
        printf("OpenSCManager failed (%d)\n", GetLastError());
        return;
    }

    // 创建服务

    schService = CreateService(
        schSCManager,              // SCM database
        SVCNAME,                   // name of service
        SVCNAME,                   // service name to display
        SERVICE_ALL_ACCESS,        // desired access
        SERVICE_WIN32_OWN_PROCESS, // service type
        SERVICE_DEMAND_START,      // start type
        SERVICE_ERROR_NORMAL,      // error control type
        szPath,                    // 服务程序的全路径名
        NULL,                      // no load ordering group
        NULL,                      // no tag identifier
        NULL,                      // no dependencies
        NULL,                      // LocalSystem account
        NULL);                     // no password
 
    if (schService == NULL)
    {
        printf("CreateService failed (%d)\n", GetLastError());
        CloseServiceHandle(schSCManager);
        return;
    }
    else printf("Service installed successfully\n");

    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}


服务创建好后,需要启动,服务才能运行,代码如下:

VOID __stdcall DoStartSvc()
{
    SERVICE_STATUS_PROCESS ssStatus;
    DWORD dwOldCheckPoint;
    DWORD dwStartTickCount;
    DWORD dwWaitTime;
    DWORD dwBytesNeeded;

    // Get a handle to the SCM database.
 
    schSCManager = OpenSCManager(
        NULL,                    // local computer
        NULL,                    // servicesActive database
        SC_MANAGER_ALL_ACCESS);  // full access rights
 
    if (NULL == schSCManager)
    {
        printf("OpenSCManager failed (%d)\n", GetLastError());
        return;
    }

    // Get a handle to the service.

    schService = OpenService(
        schSCManager,         // SCM database
        szSvcName,            // name of service
        SERVICE_ALL_ACCESS);  // full access
 
    if (schService == NULL)
    {
        printf("OpenService failed (%d)\n", GetLastError());
        CloseServiceHandle(schSCManager);
        return;
    }    

    if (!StartService(
            schService,  // handle to service
            0,           // number of arguments
            NULL) )      // no arguments
    {
        printf("StartService failed (%d)\n", GetLastError());
        CloseServiceHandle(schService);
        CloseServiceHandle(schSCManager);
        return;
    }
    else printf("Service start pending...\n");   

    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}


停止服务代码如下:

VOID __stdcall DoStopSvc()
{
    SERVICE_STATUS_PROCESS ssp;
    DWORD dwStartTime = GetTickCount();
    DWORD dwBytesNeeded;
    DWORD dwTimeout = 30000; // 30-second time-out
    DWORD dwWaitTime;

    // Get a handle to the SCM database.
 
    schSCManager = OpenSCManager(
        NULL,                    // local computer
        NULL,                    // ServicesActive database
        SC_MANAGER_ALL_ACCESS);  // full access rights
 
    if (NULL == schSCManager)
    {
        printf("OpenSCManager failed (%d)\n", GetLastError());
        return;
    }

    // Get a handle to the service.

    schService = OpenService(
        schSCManager,         // SCM database
        szSvcName,            // name of service
        SERVICE_STOP |
        SERVICE_QUERY_STATUS |
        SERVICE_ENUMERATE_DEPENDENTS);  
 
    if (schService == NULL)
    {
        printf("OpenService failed (%d)\n", GetLastError());
        CloseServiceHandle(schSCManager);
        return;
    }   

stop_cleanup:
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}




删除服务代码如下:

VOID __stdcall DoDeleteSvc()
{
    SC_HANDLE schSCManager;
    SC_HANDLE schService;
    SERVICE_STATUS ssStatus;

    // Get a handle to the SCM database.
 
    schSCManager = OpenSCManager(
        NULL,                    // local computer
        NULL,                    // ServicesActive database
        SC_MANAGER_ALL_ACCESS);  // full access rights
 
    if (NULL == schSCManager)
    {
        printf("OpenSCManager failed (%d)\n", GetLastError());
        return;
    }

    // Get a handle to the service.

    schService = OpenService(
        schSCManager,       // SCM database
        szSvcName,          // name of service
        DELETE);            // need delete access
 
    if (schService == NULL)
    {
        printf("OpenService failed (%d)\n", GetLastError());
        CloseServiceHandle(schSCManager);
        return;
    }


    if (! DeleteService(schService) )
    {
        printf("DeleteService failed (%d)\n", GetLastError());
    }
    else printf("Service deleted successfully\n");
 
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}



基本上控制服务的代码模式是:打开SCM,然后是创建或删除或开始或停止API,然后关闭打开的句柄;
具体API用法参考MSDN;

整理的代码Demo GitHub地址git@github.com:grefen/Study.git

网址:https://github.com/grefen/Study/tree/master/SCMDemo






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值