关于windows服务的编程方法

来源:互联网 发布:淘宝买东西怎么付款图 编辑:程序博客网 时间:2024/05/15 13:18
windows服务有两种,一种是驱动服务程序,另外一种是win32服务程序,我们这里只谈win32服务程序,

查看win32服务程序,可以这样:开始->运行->services.msc可以打开windows自带的服务程序控制程

序。这个大家都应该很熟悉了吧。下面来讲讲利用vc编程来对win32服务程序进行管理,包括创建、删除

已经对win32服务程序的运行状态进行管理。
在进入编程之前先要理解几样东西:
第一:服务控制管理器 service control manager(SCM),SCM在系统启动的时候就会启动,其主要的

作用有以下几个方面:
1)维持了一张已安装的服务的数据表
2)根据策略在系统启动时启动服务或者在需要的时候启动服务
4)枚举已经安装的服务
4)维持了正在运行的服务的状态信息
5)向正在运行的服务发送控制信息
6)对服务数据库的锁定管理
SCM所维持的数据库可以在注册表中找到:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services
SCM通过三类程序的方法来实现对服务的管理:Service program、Service configuration program 和

Service control program

Service Program: 也就是被注册成服务的程序主体,他必须符合服务控制器(SCM)的接口规范,这样

才能被SCM控制(包括启动,停止等等),一个服务程序内可以包含一个服务或多个服务的执行代码,但

是它们都拥有固定的三个部分:服务main函数,服务ServiceMain函数和服务Control Handler函数。
服务main函数:入口点函数,由于服务程序通常是以控制台的方式存在的,所以它们的入口点自然就是

main函数。在服务控制管理器开始一个服务程序时,会等待StartServiceCtrlDispatcher函数的执行。

如果服务类型是SERVICE_WIN32_OWN_PROCESS就会立即调用StartServiceCtrlDispatcher函数的执行;如

果服务类型是SERVICE_WIN32_SHARE_PROCESS,通常在初始化所有服务之后再调用它。

StartServiceCtrlDispatcher这个函数的作用就是把服务入口点函数和SCM连接起来。
服务ServiceMain函数:函数ServiceMain是服务的入口点。在服务控制程序请求一个新的服务启动时,

服务控制管理器启动一个服务,并发送一个开始请求到控制调度程序,而后控制调度程序创建一个新线

程来执行ServiceMain函数。ServiceMain须执行以下的任务:调用RegisterServiceCtrlHandler函数注

册一个HandlerEx函数来向服务发送控制请求信息,返回值是服务状态句柄用来向服务控制管理器传送服

务状态。初始化后调用SetServiceStatus函数设置服务状态为SERVICE_RUNNING。最后,就是执行服务所

要完成的任务。
服务Control Handler函数:每个服务都有一个控制句柄HandlerEx函数。它会在服务进程从服务控制程

序接收到一个控制请求时被控制调度程序所调用。无论何时在HandlerEx函数被调用时,都要调用

SetServiceStatus函数向服务控制管理器报告它当前的状态。在用户关闭系统时,所有的控制句柄都会

调用带有SERVICE_ACCEPT_SHUTDOW控制代码的SetServiceStatus函数来接收NSERVICE_CONTROL_SHUTDOWN

控制代码。


这里是一个 Service program的例子:
实现的功能就是打开一个端口一直监听,连接上来之后,发送一串数据,然后关闭连接。

#include "Afxwin.h"
#include "windows.h"
#include "stdio.h"
#include "winsock2.h"

#pragma comment(lib,"ws2_32")

HANDLE hMutex;
SERVICE_STATUS        ServiceStatus;
SERVICE_STATUS_HANDLE ServiceStatusHandle;

//Service Control Handler Function
void WINAPI CmdControl(DWORD dwCode)
{
        switch(dwCode)
        {
        case SERVICE_CONTROL_PAUSE:
                ServiceStatus.dwCurrentState = SERVICE_PAUSED;
                break;

        case SERVICE_CONTROL_CONTINUE:
                ServiceStatus.dwCurrentState = SERVICE_RUNNING;
                break;

        case SERVICE_CONTROL_STOP:     
                WaitForSingleObject(hMutex,INFINITE);

                ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
                ServiceStatus.dwWin32ExitCode = 0;
                ServiceStatus.dwCheckPoint    = 0;
                ServiceStatus.dwWaitHint      = 0;
                if(SetServiceStatus(ServiceStatusHandle,&ServiceStatus)==0)
                {
                        printf("SetServiceStatus in CmdControl in Switch Error !/n");
                }

                return ;

        case SERVICE_CONTROL_INTERROGATE:
                break;

        default:
                break;
        }

        if(SetServiceStatus(ServiceStatusHandle,&ServiceStatus)==0)
        {
                printf("SetServiceStatus in CmdControl out Switch Error !/n");
        }

        return ;
}

listenPort()
{
        WSADATA              wsa;
    SOCKET               sServer;
    SOCKET               sClient;
        struct               sockaddr_in sin;

        WSAStartup(MAKEWORD(2,2),&wsa);
        sServer = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(sServer==INVALID_SOCKET)
        {
                printf("Socket Error !/n");
                return -1;                                  
        }
        sin.sin_family           = AF_INET;
        sin.sin_port             = htons(20540);
        sin.sin_addr.S_un.S_addr = INADDR_ANY;

        if(bind(sServer,(const struct sockaddr *)&sin,sizeof(sin))==SOCKET_ERROR)
        {
                printf("Bind Error !/n");
                return -1;
        }
        if(listen(sServer,5)==SOCKET_ERROR)  
        {
                printf("Listen Error !/n");
                return -1;
        }
       
        hMutex=CreateMutex(NULL,FALSE,NULL);
        if(hMutex==NULL)
        {
                printf("Create Mutex Error !/n");             
        }
 
    while(1)
        {
                sClient=accept(sServer,NULL,NULL);
               
                send(sClient,"aa",sizeof("aa"),0);
                closesocket(sClient);
               
                Sleep(1000);
        }

    WSACleanup();
}

//Service ServiceMain Function
void WINAPI CmdStart(DWORD dwArgc,LPTSTR *lpArgv)
{
       
        ServiceStatus.dwServiceType             = SERVICE_WIN32;
        ServiceStatus.dwCurrentState            = SERVICE_START_PENDING;
        ServiceStatus.dwControlsAccepted        = SERVICE_ACCEPT_STOP
                                                    | SERVICE_ACCEPT_PAUSE_CONTINUE;
        ServiceStatus.dwServiceSpecificExitCode = 0;
        ServiceStatus.dwWin32ExitCode           = 0;
        ServiceStatus.dwCheckPoint              = 0;
        ServiceStatus.dwWaitHint                = 0;

        ServiceStatusHandle=RegisterServiceCtrlHandler("ntkrnl",CmdControl); //注册控制响应

程序
        if(ServiceStatusHandle==0)
        {
                printf("RegisterServiceCtrlHandler Error !/n");
                return ;
        }

        ServiceStatus.dwCurrentState = SERVICE_RUNNING;
        ServiceStatus.dwCheckPoint   = 0;
        ServiceStatus.dwWaitHint     = 0;
       
        if(SetServiceStatus(ServiceStatusHandle,&ServiceStatus)==0)
        {
                printf("SetServiceStatus in CmdStart Error !/n");
                return ;
        }
        listenPort();
       
        return ;
}

int main()
{
        SERVICE_TABLE_ENTRY DispatchTable[] =
        {
                {"ntkrnl",CmdStart},
                {NULL    ,NULL    }
        };
        StartServiceCtrlDispatcher(DispatchTable); //注意:CmdStart函数
       
        return 0;
}


Service Configuration Programs:其作用有两个方面,第一是创建、删除和枚举服务,第二是用来更

改或者查询已经安装的服务的信息。完成这些任务可以直接操作注册表,但是最好还是使用SCM 配置函

数。
SCM 配置函数需要一个SCManger对象或者一个service对象,要获得这些对象可以使用OpenSCManager函

数,或者使用OpenService、CreateService获得service对象。
这里顺便就把Service Control Programs说了,其实也就是包含一些函数可以控制服务的启动,停止,

相应的函数可以在msdn查询。

下面是一个创建服务的例子,首先使用OpenSCMagenager获得一个SCManger对象,然后使用

CreateService创建一个服务。
#include "windows.h"
#include "stdio.h"
#include "Winsvc.h"
#include "TCHAR.h"
#pragma comment(lib,"Advapi32.lib")

int main()
{
       
    SC_HANDLE                schManager;
        SC_HANDLE                schService;
        DWORD                    dwBytesNeeded;
        LPQUERY_SERVICE_CONFIG   lpServiceConfig      = NULL;
        LPSERVICE_DESCRIPTION    lpServiceDescription = NULL;
    SERVICE_STATUS           ServiceStatus;
        DWORD                    dwIndex;

        schManager = OpenSCManager

(NULL,NULL,SC_MANAGER_ALL_ACCESS);//SC_MANAGER_ALL_ACCESS);
        if(schManager == NULL)
        {
                printf("OpenschManager Error: %d/n",GetLastError());
                return FALSE;
        }
        SC_HANDLE hdlServ = CreateService(
                                        schManager,
                                        _T("test"),
                                        _T("test"),
                                        SC_MANAGER_ALL_ACCESS,
                                        0x00000010,
                                        3,
                                        //SERVICE_ALL_ACCESS,
                                        //SERVICE_WIN32_OWN_PROCESS,
                                        //SERVICE_DEMAND_START,
                                        SERVICE_ERROR_NORMAL,
                                        _T("d://test.exe"), //这个就是由上面那个程序生成的

exe文件
                                        NULL,NULL,NULL,NULL,NULL
                                        );
        if (hdlServ == NULL)
        {
                DWORD gg = GetLastError();
                printf("error!/n");
        }
        hdlServ = OpenService(schManager,_T

("test"),SC_MANAGER_ALL_ACCESS);//SERVICE_ALL_ACCESS);
        if (hdlServ == NULL)
        {
                printf("OpenSerivce error/n");
        }
        /*
        if (!DeleteService(hdlServ))
        {
                printf("delete error/n");
        }
        */
        //查看服务状态
        SERVICE_STATUS ss;
    if(QueryServiceStatus(hdlServ, &ss) == FALSE)
        {
                printf("Error Service Status! %d/n", GetLastError());
                return FALSE;
        }
        //如果服务已经启动,则退出
        if(ss.dwCurrentState == SERVICE_RUNNING)
                return TRUE;

        //启动服务
    StartService(hdlServ, 0, NULL);   
        Sleep(1000);

        //查看服务状态
    if(QueryServiceStatus(hdlServ, &ss) == FALSE)
        {
                printf("Error Service Status! %d/n", GetLastError());
                return FALSE;
        }
        if(ss.dwCurrentState != SERVICE_RUNNING)
        {
                printf("Error in Starting Service! %d/n", GetLastError());
                CloseHandle(hdlServ);
                return FALSE;
        }

        printf("/nend/n");
        return 0;
}

 

最后,再举一个例子。
ServiceAll()枚举所有的服务,并打印出来
ServiceInformation(char *szServiceName)查询特定服务的具体信息

#include "windows.h"
#include "stdio.h"
#include "Winsvc.h"
#include "TCHAR.h"
#pragma comment(lib,"Advapi32.lib")
BOOL  ServiceAll()
{
    SC_HANDLE   schManager;
        DWORD       dwServiceType;
        DWORD       dwServiceState;
        DWORD       dwIndex;
        DWORD       cbBufSize;
        DWORD       ResumeHandle;
        DWORD       cbBytesNeeded;
        DWORD       ServicesReturned;
        ENUM_SERVICE_STATUS   EnumStatus[512];

        schManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
        if(schManager == NULL)
        {
                printf("OpenschManager Error: %d/n",GetLastError());
                return FALSE;
        }

        dwServiceType    = SERVICE_WIN32;
        dwServiceState   = SERVICE_STATE_ALL;
        cbBufSize        = sizeof(EnumStatus);
        cbBytesNeeded    = 0;
        ServicesReturned = 0;
        ResumeHandle     = 0;
        if(!EnumServicesStatus(schManager,dwServiceType,dwServiceState,
                                   EnumStatus,cbBufSize,&cbBytesNeeded,
                                                   &ServicesReturned,&ResumeHandle))
        {
        cbBufSize   += cbBytesNeeded;
                if(!EnumServicesStatus(schManager,dwServiceType,dwServiceState,
                                       EnumStatus,cbBufSize,&cbBytesNeeded,
                                                   &ServicesReturned,&ResumeHandle))
                {
                        printf("EnumServicesStatus Error: %d/n",GetLastError());
                        return FALSE;
                }
                else
                {
                printf("Services:/t %d/n",ServicesReturned);
                }
        }

        printf("/t/t=== Services ===/n/n");
        printf("%-20s/t%-10s%s/n/n","ServiceName","Status","DisplayName");
        for(dwIndex = 0;dwIndex < ServicesReturned; dwIndex ++)
        {
                printf("%-20s/t",EnumStatus[dwIndex].lpServiceName);
                switch(EnumStatus[dwIndex].ServiceStatus.dwCurrentState)
                {
                case SERVICE_STOPPED:
                        printf("%-10s","Stopped");
                        break;
                case SERVICE_START_PENDING:
                        printf("%-10s","Starting");
                        break;
                case SERVICE_STOP_PENDING:
                        printf("%-10s","Stopping");
                        break;
                case SERVICE_RUNNING:
                        printf("%-10s","Running");
                        break;
                case SERVICE_CONTINUE_PENDING:
                        printf("%-10s","Continue");
                        break;
                case SERVICE_PAUSE_PENDING:
                        printf("%-10s","Pausing");
                        break;
                case SERVICE_PAUSED:
                        printf("%-10s","Paused");
                        break;
                default:
                        printf("%-10s","");
                        break;
                }
                printf("%s/n",EnumStatus[dwIndex].lpDisplayName);
        }
        printf("/nTotal:/t %d/n",ServicesReturned);


        if(schManager != NULL)
        {
                CloseServiceHandle(schManager);
        }

        return TRUE;
}

BOOL  ServiceInformation(char *szServiceName)
{
    SC_HANDLE                schManager;
        SC_HANDLE                schService;
        DWORD                    dwBytesNeeded;
        LPQUERY_SERVICE_CONFIG   lpServiceConfig      = NULL;
        LPSERVICE_DESCRIPTION    lpServiceDescription = NULL;
    SERVICE_STATUS           ServiceStatus;
        DWORD                    dwIndex;

        schManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
        if(schManager == NULL)
        {
                printf("OpenschManager Error: %d/n",GetLastError());
                return FALSE;
        }

        schService = OpenService(schManager,szServiceName,SERVICE_ALL_ACCESS);
        if(schService == NULL)
        {
                if(GetLastError() == ERROR_INVALID_NAME)
                {
                        printf("%s no Found !/n",szServiceName);
                        return TRUE;
                }
                printf("OpenService Error: %d/n",GetLastError());
                return FALSE;
        }

    lpServiceConfig = (LPQUERY_SERVICE_CONFIG)malloc(1024*8);
        printf("/t/t=== Configuration ===/n/n");
        if(!QueryServiceConfig(schService,lpServiceConfig,1024*8,&dwBytesNeeded))
        {
                printf("QueryServiceConfig Error: %d/n",GetLastError());
        }
        else
        {
                if(lpServiceConfig->lpDisplayName != NULL)
                        printf("DisplayName:/t %s/n",lpServiceConfig->lpDisplayName);
                if(lpServiceConfig->dwTagId != 0)
                        printf("TagID:/t/t %d/n",lpServiceConfig->dwTagId);
                printf("FilePath:/t %s/n",lpServiceConfig->lpBinaryPathName);
                printf("ServiceType:/t ");
                switch(lpServiceConfig->dwServiceType)
                {
                case SERVICE_WIN32_OWN_PROCESS:
                        printf("Win32 Own Process/n");
                        break;
                case SERVICE_WIN32_SHARE_PROCESS:
                        printf("Win32 Share Process/n");
                        break;
                default:
                        printf("/n");
                        break;
                }
                printf("StartType:/t ");
                switch(lpServiceConfig->dwStartType)
                {
                case SERVICE_AUTO_START:
                        printf("Auto Start/n");
                        break;
                case SERVICE_BOOT_START:
                        printf("Boot Start/n");
                        break;
                case SERVICE_DEMAND_START:
                        printf("Demand Start/n");
                        break;
                case SERVICE_DISABLED:
                        printf("Disabled/n");
                        break;
                case SERVICE_SYSTEM_START:
                        printf("System Start/n");
                        break;
                default:
                        printf("/n");
                        break;
                }
                printf("ErrorControl:/t ");
                switch(lpServiceConfig->dwErrorControl)
                {
                case SERVICE_ERROR_IGNORE:
                        printf("Ignore/n");
                        break;
                case SERVICE_ERROR_NORMAL:
                        printf("Normal/n");
                        break;
                case SERVICE_ERROR_SEVERE:
                        printf("Server/n");
                        break;
                case SERVICE_ERROR_CRITICAL:
                        printf("Critical/n");
                        break;
                default:
                        printf("/n");
                        break;
                }

                if(lpServiceConfig->lpServiceStartName != NULL)
                        printf("StartName:/t %s/n",lpServiceConfig->lpServiceStartName);

                printf("LoadOrderGroup:/t ");
                if(lpServiceConfig->lpLoadOrderGroup[0] != '/0')
                {
                        printf("%s/n",lpServiceConfig->lpLoadOrderGroup);
                }
                else
                {
                        printf("(none)/n");
                }

                dwIndex = 0;
                printf("Dependendencies: ");
                if(lpServiceConfig->lpDependencies[0] != '/0')
                {
                        while(lpServiceConfig->lpDependencies[dwIndex]   != '/0'
                          ||  lpServiceConfig->lpDependencies[dwIndex+1] != '/0')
                        {
                                if(lpServiceConfig->lpDependencies[dwIndex]  == '/0')
                                {
                                        printf("; ");
                                }
                                else
                                {
                                        printf("%c",lpServiceConfig->lpDependencies

[dwIndex]);
                                }
                                dwIndex ++;
                        }
                }
                else
                {
                        printf("(none)");
                }
                printf("/n");
        }
    if(!QueryServiceStatus(schService,&ServiceStatus))
        {
                printf("QueryServiceStatus Error: %d/n",GetLastError());
        }
        else
        {
                printf("CurrentState:/t ");
                switch(ServiceStatus.dwCurrentState)
                {
                case SERVICE_CONTINUE_PENDING:
                        printf("Continue/n");
                        break;
                case SERVICE_PAUSE_PENDING:
                        printf("Pausing/n");
                        break;
                case SERVICE_PAUSED:
                        printf("Paused/n");
                        break;
                case SERVICE_RUNNING:
                        printf("Running/n");
                        break;
                case SERVICE_START_PENDING:
                        printf("Starting/n");
                        break;
                case SERVICE_STOP_PENDING:
                        printf("Stopping/n");
                        break;
                case SERVICE_STOPPED:
                        printf("Stopped/n");
                        break;
        default:
                        printf("/n");
                        break;
                }
                printf("Win32ExitCode:/t %d/n",ServiceStatus.dwWin32ExitCode);
                printf("SpecialExitCode: %d/n",ServiceStatus.dwServiceSpecificExitCode);
                printf("CheckPoint:/t %d/n",ServiceStatus.dwCheckPoint);
                printf("WaitHint:/t %d/n",ServiceStatus.dwWaitHint);
        }

        lpServiceDescription = (LPSERVICE_DESCRIPTION) malloc(1024*8);
        if(!QueryServiceConfig2(schService,SERVICE_CONFIG_DESCRIPTION,(LPBYTE)

lpServiceDescription,
                                    8*1024,&dwBytesNeeded))
        {
                printf("QueryServiceConfig2 Error: %d/n",GetLastError());
        }
        else
        {
                printf("Description:/t %s/n",lpServiceDescription->lpDescription);
        }


        if(lpServiceConfig != NULL)
        {
                free(lpServiceConfig);
        }
        if(lpServiceDescription != NULL)
        {
                free(lpServiceDescription);
        }
        if(schService != NULL)
        {
                CloseServiceHandle(schService);
        }
        if(schManager != NULL)
        {
                CloseServiceHandle(schManager);
        }

        return TRUE;
}

BOOL  ServiceControl(char *szServiceName,DWORD dwSignature)
{
    SC_HANDLE         schManager;
        SC_HANDLE         schService;
    SERVICE_STATUS    ServiceStatus;

        schManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
        if(schManager == NULL)
        {
                printf("OpenschManager Error: %d/n",GetLastError());
                return FALSE;
        }

        schService = OpenService(schManager,szServiceName,SERVICE_ALL_ACCESS);
        if(schService == NULL)
        {
                if(GetLastError() == ERROR_INVALID_NAME)
                {
                        printf("%s no Found !/n",szServiceName);
                        return TRUE;
                }
                printf("OpenService Error: %d/n",GetLastError());
                return FALSE;
        }

        if(!QueryServiceStatus(schService,&ServiceStatus))
        {
                printf("QueryServiceStatus Error: %d/n",GetLastError());
        }
        else
        {
                if(dwSignature == 0)
                {
                        if(ServiceStatus.dwCurrentState == SERVICE_RUNNING)
                        {
                        printf("Already Running !/n");
                        }
                        else
                        {
                                if(!StartService(schService,0,NULL))
                                {
                                        printf("Start %s Error: %

d/n",szServiceName,GetLastError());
                                }
                                else
                                {
                                        printf("Start %s Success !/n",szServiceName);
                                }
                        }
                }
                else if(dwSignature == 1)
                {
                        if(ServiceStatus.dwCheckPoint == SERVICE_STOPPED)
                        {
                        printf("Already Stopped !/n");
                        }
                        else
                        {
                                if(!ControlService

(schService,SERVICE_CONTROL_STOP,&ServiceStatus))
                                {
                                        printf("Stop %s Error: %

d/n",szServiceName,GetLastError());
                                }
                                else
                                {
                                        Sleep(50);
                                        while(ServiceStatus.dwCheckPoint ==

SERVICE_STOP_PENDING)
                                        {
                                                Sleep(30);
                                                QueryServiceStatus

(schService,&ServiceStatus);
                                        }
                                        if(ServiceStatus.dwCurrentState != SERVICE_STOPPED)
                                        {
                                        printf("Stop %s Error: %

d/n",szServiceName,GetLastError());
                                        }
                                        else
                                        {
                                                printf("Stop %s Success !

/n",szServiceName);
                                        }
                                }
                        }
                }
                else if(dwSignature == 2)
                {
                        if(ServiceStatus.dwCurrentState != SERVICE_STOPPED)
                        {
                                if(!ControlService

(schService,SERVICE_CONTROL_STOP,&ServiceStatus))
                                {
                                        printf("Stop %s Error: %

d/n",szServiceName,GetLastError());
                                        return FALSE;
                                }
                        }

                        if(!DeleteService(schService))
                        {
                                printf("Delete %s Error: %d/n",szServiceName,GetLastError

());
                        }
                        else
                        {
                                printf("Delte %s Success !/n",szServiceName,GetLastError

());
                        }
                }
        }

        if(schService != NULL)
        {
                CloseServiceHandle(schService);
        }
        if(schManager != NULL)
        {
                CloseServiceHandle(schManager);
        }

        return TRUE;
}


int main()
{
        ServiceAll();                   //查询所有服务
        ServiceInformation("Serv-u");   //查询Serv-u这个服务

        printf("/nend/n");
        return 0;
}


后记:
开始没有懂起服务程序还有一定的规范,自己理解可以把任意的程序注册成服务,并且在网上看到一篇

文章叫“让程序以服务形式运行”,他利用instsrv.exe把QQ注册成服务了,然后我测试发现确实可以注

册成服务成功,但是不能正常启动,搞的我整了N久,后来也去搞了instsrv.exe来测试,发觉确实不能

把任意程序注册成服务。累啊!gali

 
原创粉丝点击