基于visual c++之windows核心编程代码分析(9)实现Windows服务并安装,控制

//我们进行Windows编程的时候,经常涉及到Windows服务编程,针对Windows服务我们该怎么编程呢,
//我们先来实现一个Windows服务并实现之,请见注释代码分析。

/* 头文件 */
#include <windows.h>     
/* 全局变量 */
SERVICE_STATUS          SplSrvServiceStatus;      
SERVICE_STATUS_HANDLE   SplSrvServiceStatusHandle;      
/* 函数声明 */
VOID SvcDebugOut(LPSTR String, DWORD Status);     
VOID WINAPI SplSrvServiceCtrlHandler (DWORD opcode);      
VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv);      
DWORD SplSrvServiceInitialization (DWORD argc, LPTSTR *argv,      
                                   DWORD *specificError);      
          
/*************************************    
* VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv)    
* 功能    服务启动函数    
*    
* 参数    未使用    
**************************************/
VOID WINAPI SplSrvServiceStart (DWORD argc, LPTSTR *argv)      
{      
    DWORD status;      
    DWORD specificError;      
    // 填充SERVICE_STATUS 结构     
    SplSrvServiceStatus.dwServiceType        = SERVICE_WIN32;      
    SplSrvServiceStatus.dwCurrentState            
        = SERVICE_START_PENDING;        // 服务在运行     
    SplSrvServiceStatus.dwControlsAccepted        
        = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;      
    SplSrvServiceStatus.dwWin32ExitCode      = 0;      
    SplSrvServiceStatus.dwServiceSpecificExitCode = 0;      
    SplSrvServiceStatus.dwCheckPoint         = 0;      
    SplSrvServiceStatus.dwWaitHint           = 0;      
    // 注册服务控制请求处理例程     
    SplSrvServiceStatusHandle = RegisterServiceCtrlHandler(      
        "Sample_Srv",   // 服务名,在创建服务时使用了     
        // SERVICE_WIN32_OWN_PROCESS,因此本参数被忽略。     
        SplSrvServiceCtrlHandler);  // 控制请求处理例程,函数名     
          
    if (SplSrvServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)      
    {      
        SvcDebugOut(" [SPLSRV_SERVICE] RegisterServiceCtrlHandler "
            "failed %dn", GetLastError());      
        return;      
    }       
    // 初始化工作,本示例未使用,函数为空     
    status = SplSrvServiceInitialization(argc,argv, &specificError);       
    // 初始化出错,用户自行修改     
    if (status != NO_ERROR)      
    {      
        SplSrvServiceStatus.dwCurrentState       = SERVICE_STOPPED;      
        SplSrvServiceStatus.dwCheckPoint         = 0;      
        SplSrvServiceStatus.dwWaitHint           = 0;      
        SplSrvServiceStatus.dwWin32ExitCode      = status;      
        SplSrvServiceStatus.dwServiceSpecificExitCode = specificError;      
          
        SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus);      
        return;      
    }      
    // 初始化完成,设置运行状态     
    SplSrvServiceStatus.dwCurrentState       = SERVICE_RUNNING;      
    SplSrvServiceStatus.dwCheckPoint         = 0;      
    SplSrvServiceStatus.dwWaitHint           = 0;      
          
    if (!SetServiceStatus (SplSrvServiceStatusHandle, &SplSrvServiceStatus))      
    {      
        status = GetLastError();      
        SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ldn",status);      
    }      
    // 用户自行修改,用于完成服务的工作     
    SvcDebugOut(" [SPLSRV_SERVICE] Returning the Main Thread n",0);      
          
    return;      
}      
          
          
/*************************************    
* DWORD SplSrvServiceInitialization(DWORD   argc,     
*   LPTSTR  *argv,     
*   DWORD *specificError)    
* 功能    初始化,这里未进行任何工作,留待读者修改    
*    
* 参数        
**************************************/
DWORD SplSrvServiceInitialization(DWORD   argc,      
                                  LPTSTR  *argv,      
                                  DWORD *specificError)      
{      
    return(0);      
}     
          
/*************************************    
* VOID WINAPI SplSrvServiceCtrlHandler (DWORD Opcode)    
* 功能    服务控制请求的处理函数,与ControlService函数配合。    
*    
* 参数    服务控制码    
**************************************/
VOID WINAPI SplSrvServiceCtrlHandler (DWORD Opcode)      
{      
    DWORD status;      
    switch(Opcode)      
    {      
    case SERVICE_CONTROL_PAUSE:      
        // 完成相关功能     
        SplSrvServiceStatus.dwCurrentState = SERVICE_PAUSED;      
        break;      
    case SERVICE_CONTROL_CONTINUE:      
        // 完成相关功能     
        SplSrvServiceStatus.dwCurrentState = SERVICE_RUNNING;      
        break;      
    case SERVICE_CONTROL_STOP:      
        // 完成相关功能     
        SplSrvServiceStatus.dwWin32ExitCode = 0;      
        SplSrvServiceStatus.dwCurrentState  = SERVICE_STOPPED;      
        SplSrvServiceStatus.dwCheckPoint    = 0;      
        SplSrvServiceStatus.dwWaitHint      = 0;      
          
        if (!SetServiceStatus (SplSrvServiceStatusHandle,      
            &SplSrvServiceStatus))     
        {      
            status = GetLastError();      
            SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ldn",      
                status);      
        }       
        SvcDebugOut(" [SPLSRV_SERVICE] Leaving SplSrvService n",0);      
        return;      
    case SERVICE_CONTROL_INTERROGATE:      
        // 收到此请求后发出声响,演示服务控制请求的处理过程,读者可自行修改     
        MessageBeep(MB_OK);     
        break;      
    default:      
        SvcDebugOut(" [SPLSRV_SERVICE] Unrecognized opcode %ldn",      
            Opcode);      
    }      
    // 当前状态     
    if (!SetServiceStatus (SplSrvServiceStatusHandle,  &SplSrvServiceStatus))      
    {      
        status = GetLastError();      
        SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ldn",      
            status);      
    }      
    return;      
}     
/*************************************    
* void main( )     
* 功能    程序入口函数,注册服务启动函数等。    
*    
* 参数    服务控制码    
**************************************/
void main( )      
{      
    // 设置SERVICE_TABLE_ENTRY 数据结构,以NULL 结构结束,     
    // 作为StartServiceCtrlDispatcher 函数的参数。     
    SERVICE_TABLE_ENTRY   DispatchTable[] =      
    {      
        { "Sample_Srv", (LPSERVICE_MAIN_FUNCTION) SplSrvServiceStart },      
        { NULL, NULL }      
    };      
    if (!StartServiceCtrlDispatcher( DispatchTable))      
    {      
        SvcDebugOut(" [SPLSRV_SERVICE] StartServiceCtrlDispatcher (%d)n",      
            GetLastError());      
    }      
}      
/*************************************    
* VOID SvcDebugOut(LPSTR String, DWORD Status)     
* 功能    显示信息给调试器。    
*    
* 参数    LPSTR String    消息字符串    
*       DWORD Status    状态    
**************************************/
VOID SvcDebugOut(LPSTR String, DWORD Status)      
{      
    CHAR  Buffer[1024];      
    if (strlen(String) < 1000)      
    {      
        wsprintf(Buffer, String, Status);      
        OutputDebugString(Buffer);      
    }      
}




//具体实现代码如下,请见代码分析
**************************************/     
/* 头文件 */
#include <windows.h>     
#include <tchar.h>     
#include <stdio.h>     
/* 全局变量 */
SC_HANDLE schService;     
SC_HANDLE schSCManager;     
LPTSTR szServiceName = TEXT("Sample_Srv");     
          
/*************************************    
* BOOL CreateSampleService(LPTSTR szPath, LPSTR szServiceName)     
* 功能    创建服务    
*    
* 参数    
*       SC_HANDLE schSCManager,SCM句柄    
*       LPTSTR szPath, 服务程序的路径    
*       LPSTR szServiceName, 服务名    
**************************************/
BOOL CreateSampleService(      
                         SC_HANDLE schSCManager,     
                         LPTSTR szPath,     
                         LPSTR szServiceName)      
{      
    // 创建服务     
    schService = CreateService(      
        schSCManager,               // SCM 句柄     
        szServiceName,              // 服务名     
        "Service sample",           // 显示的服务名     
        SERVICE_ALL_ACCESS,         // 存取权限     
        SERVICE_WIN32_OWN_PROCESS,  // 服务类别     
        SERVICE_DEMAND_START,       // 启动类别     
        SERVICE_ERROR_NORMAL,       // 错误控制类别     
        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());      
        return FALSE;     
    }     
    else
    {     
        printf("CreateService succeededn");      
        CloseServiceHandle(schService);      
        return TRUE;     
    }     
}     
          
/*************************************    
* BOOL DeleteSampleService(LPTSTR szNameOfService)     
* 功能    删除服务    
*    
* 参数    LPTSTR szNameOfService  服务的名字    
**************************************/
BOOL DeleteSampleService(LPTSTR szNameOfService)      
{      
    schService = OpenService(      
        schSCManager,       // SCM 句柄      
        szNameOfService,    // 服务名     
        DELETE);            // 可删除     
          
    if (schService == NULL)     
    {      
        printf("OpenService failed (%d)n", GetLastError());      
        return FALSE;     
    }     
    // 删除服务     
    if (! DeleteService(schService) )      
    {     
        printf("DeleteService failed (%d)n", GetLastError());      
        return FALSE;     
    }     
    else 
        printf("DeleteService succeededn");      
    // 关闭句柄     
    CloseServiceHandle(schService);      
    return TRUE;     
}     
/*************************************    
* void main( int argc, TCHAR *argv[] )    
* 功能    演示    
*    
* 参数    未使用    
**************************************/
void main( int argc, TCHAR *argv[] )      
{     
    TCHAR szBinFilePath[MAX_PATH];     
    PTCHAR pTemp;     
    DWORD dwStopError;     
    // 构造服务可执行程序的路径     
    GetModuleFileName(NULL,szBinFilePath,MAX_PATH);     
    pTemp = szBinFilePath+lstrlen(szBinFilePath);     
    while(*--pTemp!='');     
    lstrcpy(pTemp,TEXT("SplSrv.exe"));     
          
    // 打开 SCM     
    schSCManager = OpenSCManager(      
        NULL,                    // local machine      
        NULL,                    // ServicesActive database      
        SC_MANAGER_ALL_ACCESS);  // full access rights      
          
    if (NULL == schSCManager)      
        printf("OpenSCManager failed (%d)n", GetLastError());     
          
    // 创建服务     
    CreateSampleService(schSCManager, szBinFilePath, szServiceName);     
    // 启动服务     
    StartSampleService(schSCManager,szServiceName);     
    // 发送请求控制     
    ControlSampleService(SERVICE_CONTROL_INTERROGATE);     
    ControlSampleService(SERVICE_CONTROL_CONTINUE);     
    // 停止服务     
    dwStopError = StopService( schSCManager, szServiceName,      
        TRUE, 1000);     
          
    if(ERROR_SUCCESS == dwStopError)     
    {     
        printf("Service Stopedn");      
    }      
    else
    {     
        printf("Service stoped error (%u)n",dwStopError);      
    }     
    // 删除服务     
    DeleteSampleService(szServiceName);     
    CloseServiceHandle(schSCManager);      
}



//然后我们如何控制服务呢,我们来实现启动、停止服务,向服务发送请求。
/* 头文件 */
#include <windows.h>     
#include <tchar.h>     
#include <stdio.h>     
/* 全局变量 */
extern SC_HANDLE schService;    // 在init.c中定义,下同     
extern SC_HANDLE schSCManager;     
extern LPTSTR szServiceName;     
          
/*************************************    
* BOOL StartSampleService(SC_HANDLE schSCManager,LPTSTR szServiceName)     
* 功能    启动服务    
*    
* 参数    SC_HANDLE schSCManager  SCM 句柄    
*       LPTSTR szServiceName    服务名    
**************************************/
BOOL StartSampleService(SC_HANDLE schSCManager,LPTSTR szServiceName)      
{      
    SC_HANDLE schService;     
    SERVICE_STATUS_PROCESS ssStatus;      
    DWORD dwOldCheckPoint;      
    DWORD dwStartTickCount;     
    DWORD dwWaitTime;     
    DWORD dwBytesNeeded;     
    // 打开服务     
    schService = OpenService(      
        schSCManager,           // SCM database      
        szServiceName,          // service name     
        SERVICE_ALL_ACCESS);      
    if (schService == NULL)      
    {      
        return 0;      
    }     
    // 启动服务     
    if (!StartService(     
        schService,  // handle to service      
        0,           // number of arguments      
        NULL) )      // no arguments      
    {     
        printf("Service start error (%u).n",GetLastError());      
        return 0;      
    }     
    else 
    {     
        printf("Service start pending.n");      
    }     
          
    // 验证状态     
    if (!QueryServiceStatusEx(      
        schService,             // handle to service      
        SC_STATUS_PROCESS_INFO, // info level     
        (LPBYTE)&ssStatus,              // address of structure     
        sizeof(SERVICE_STATUS_PROCESS), // size of structure     
        &dwBytesNeeded ) )              // if buffer too small     
    {     
        return 0;      
    }     
          
    // tick count & checkpoint.     
    dwStartTickCount = GetTickCount();     
    dwOldCheckPoint = ssStatus.dwCheckPoint;     
    // 查询状态,确定 PENDING 状态结束     
    while (ssStatus.dwCurrentState == SERVICE_START_PENDING)      
    {      
        // 等待一段时间     
        dwWaitTime = ssStatus.dwWaitHint / 10;     
        if( dwWaitTime < 1000 )     
            dwWaitTime = 1000;     
        else if ( dwWaitTime > 10000 )     
            dwWaitTime = 10000;     
        Sleep( dwWaitTime );     
        // 再次查询     
        if (!QueryServiceStatusEx(      
            schService,             // handle to service      
            SC_STATUS_PROCESS_INFO, // info level     
            (LPBYTE)&ssStatus,              // address of structure     
            sizeof(SERVICE_STATUS_PROCESS), // size of structure     
            &dwBytesNeeded ) )              // if buffer too small     
            break;      
        if ( ssStatus.dwCheckPoint > dwOldCheckPoint )     
        {     
            // 进程创建中     
            dwStartTickCount = GetTickCount();     
            dwOldCheckPoint = ssStatus.dwCheckPoint;     
        }     
        else
        {     
            if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)     
            {     
                // WaitHint 时间到     
                break;     
            }     
        }     
    }      
    // 关闭句柄     
    CloseServiceHandle(schService);      
    // 判断是否创建成功(状态由PENDING变为RUNNING)     
    if (ssStatus.dwCurrentState == SERVICE_RUNNING)      
    {     
        printf("StartService SUCCESS.n");      
        return 1;     
    }     
    else 
    {      
        printf("nService not started. n");     
        printf("  Current State: %dn", ssStatus.dwCurrentState);      
        printf("  Exit Code: %dn", ssStatus.dwWin32ExitCode);      
        printf("  Service Specific Exit Code: %dn",      
            ssStatus.dwServiceSpecificExitCode);      
        printf("  Check Point: %dn", ssStatus.dwCheckPoint);      
        printf("  Wait Hint: %dn", ssStatus.dwWaitHint);      
        return 0;     
    }      
}     
          
/*************************************    
* DWORD StopService( SC_HANDLE hSCM,     
LPTSTR szServiceName,     
BOOL fStopDependencies,     
DWORD dwTimeout )      
* 功能    停止服务    
*    
* 参数    SC_HANDLE hSCM          SCM 句柄    
*       LPTSTR szServiceName    服务名    
*       BOOL fStopDependencies  是否结束依赖的服务    
*       DWORD dwTimeout         超时    
**************************************/
DWORD StopService(SC_HANDLE hSCM,      
                  LPTSTR szServiceName,      
                  BOOL fStopDependencies,      
                  DWORD dwTimeout )      
{     
    SERVICE_STATUS_PROCESS ssp;     
    SERVICE_STATUS ss;     
    DWORD dwStartTime = GetTickCount();     
    DWORD dwBytesNeeded;     
    // 打开服务     
    SC_HANDLE hService = OpenService(      
        hSCM,          // SCM 句柄      
        szServiceName,          // 服务名     
        SERVICE_ALL_ACCESS);      
          
    // 查询状态,确定是否已经停止     
    if ( !QueryServiceStatusEx(      
        hService,      
        SC_STATUS_PROCESS_INFO,     
        (LPBYTE)&ssp,      
        sizeof(SERVICE_STATUS_PROCESS),     
        &dwBytesNeeded ) )     
    {     
        return GetLastError();     
    }     
    if ( ssp.dwCurrentState == SERVICE_STOPPED )      
    {     
        return ERROR_SUCCESS;     
    }     
    // 如果是 STOP_PENDING 状态,则只需等待     
    while ( ssp.dwCurrentState == SERVICE_STOP_PENDING )      
    {     
        Sleep( ssp.dwWaitHint );     
        // 循环查询,直到状态改变     
        if ( !QueryServiceStatusEx(      
            hService,      
            SC_STATUS_PROCESS_INFO,     
            (LPBYTE)&ssp,      
            sizeof(SERVICE_STATUS_PROCESS),     
            &dwBytesNeeded ) )     
        {     
            return GetLastError();     
        }     
        if ( ssp.dwCurrentState == SERVICE_STOPPED )     
        {     
            return ERROR_SUCCESS;     
        }     
        if ( GetTickCount() - dwStartTime > dwTimeout )     
        {     
            return ERROR_TIMEOUT;     
        }     
    }     
          
    // 先结束依赖服务     
    if ( fStopDependencies )      
    {     
        DWORD i;     
        DWORD dwBytesNeeded;     
        DWORD dwCount;     
          
        LPENUM_SERVICE_STATUS   lpDependencies = NULL;     
        ENUM_SERVICE_STATUS     ess;     
        SC_HANDLE               hDepService;     
          
        // 使用 0 大小的 buf,获取buf的大小     
        // 如果 EnumDependentServices 直接返回成功,说明没有依赖服务     
        if ( !EnumDependentServices( hService, SERVICE_ACTIVE,      
            lpDependencies, 0, &dwBytesNeeded, &dwCount ) )      
        {     
            if ( GetLastError() != ERROR_MORE_DATA )     
                return GetLastError(); // Unexpected error     
          
            // 分配缓冲区存储依赖服务的数据     
            lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc(      
                GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded );     
          
            if ( !lpDependencies )     
                return GetLastError();     
          
            __try {     
                // 获得依赖服务     
                if ( !EnumDependentServices( hService, SERVICE_ACTIVE,      
                    lpDependencies, dwBytesNeeded, &dwBytesNeeded,     
                    &dwCount ) )     
                    return GetLastError();     
          
                for ( i = 0; i < dwCount; i++ )      
                {     
                    ess = *(lpDependencies + i);     
          
                    // 打开服务     
                    hDepService = OpenService( hSCM, ess.lpServiceName,      
                        SERVICE_STOP | SERVICE_QUERY_STATUS );     
                    if ( !hDepService )     
                        return GetLastError();     
          
                    __try {     
                        // 结束服务     
                        if ( !ControlService( hDepService,      
                            SERVICE_CONTROL_STOP,     
                            &ss ) )     
                            return GetLastError();     
          
                        // 等待服务结束     
                        while ( ss.dwCurrentState != SERVICE_STOPPED )      
                        {     
                            Sleep( ss.dwWaitHint );     
                            if ( !QueryServiceStatusEx(      
                                hDepService,      
                                SC_STATUS_PROCESS_INFO,     
                                (LPBYTE)&ssp,      
                                sizeof(SERVICE_STATUS_PROCESS),     
                                &dwBytesNeeded ) )     
                                return GetLastError();     
          
                            if ( ss.dwCurrentState == SERVICE_STOPPED )     
                                break;     
          
                            if ( GetTickCount() - dwStartTime > dwTimeout )     
                                return ERROR_TIMEOUT;     
                        }     
          
                    }      
                    __finally      
                    {     
                        // 关闭服务     
                        CloseServiceHandle( hDepService );     
          
                    }     
                }     
            }      
            __finally      
            {     
                // 释放内存     
                HeapFree( GetProcessHeap(), 0, lpDependencies );     
            }     
        }      
    }     
          
    // 所有的依赖服务已经结束,结束指定服务     
    if ( !ControlService( hService, SERVICE_CONTROL_STOP, &ss ) )     
        return GetLastError();     
    while ( ss.dwCurrentState != SERVICE_STOPPED )      
    {     
        Sleep( ss.dwWaitHint );     
        if ( !QueryServiceStatusEx(      
            hService,      
            SC_STATUS_PROCESS_INFO,     
            (LPBYTE)&ssp,      
            sizeof(SERVICE_STATUS_PROCESS),     
            &dwBytesNeeded ) )     
            return GetLastError();     
          
        if ( ss.dwCurrentState == SERVICE_STOPPED )     
            break;     
          
        if ( GetTickCount() - dwStartTime > dwTimeout )     
            return ERROR_TIMEOUT;     
    }     
    return ERROR_SUCCESS;     
}     
          
/*************************************    
* BOOL ControlSampleService(DWORD fdwControl)     
* 功能    向服务发送控制码    
*    
* 参数    DWORD fdwControl        控制码值    
*       SCM 句柄,服务名直接使用全局变量    
**************************************/
BOOL ControlSampleService(DWORD fdwControl)      
{      
    SERVICE_STATUS ssStatus;      
    DWORD fdwAccess;      
    DWORD dwStartTickCount, dwWaitTime;     
          
    // Access     
    switch (fdwControl)      
    {      
    case SERVICE_CONTROL_STOP:      
        fdwAccess = SERVICE_STOP;      
        break;      
    case SERVICE_CONTROL_PAUSE:      
    case SERVICE_CONTROL_CONTINUE:      
        fdwAccess = SERVICE_PAUSE_CONTINUE;      
        break;      
    case SERVICE_CONTROL_INTERROGATE:      
        fdwAccess = SERVICE_INTERROGATE;      
        break;      
    default:      
        fdwAccess = SERVICE_INTERROGATE;      
    }      
          
    // 打开服务     
    schService = OpenService(      
        schSCManager,        // SCManager 句柄      
        szServiceName,       // 服务名     
        fdwAccess);          // 存取权限     
    if (schService == NULL)      
    {     
        printf("OpenService failed (%d)n", GetLastError());      
        return FALSE;     
    }     
          
    // 发送控制码     
    if (! ControlService(      
        schService,   // 服务的句柄     
        fdwControl,   // 控制码     
        &ssStatus) )  // 状态     
    {     
        printf("ControlService failed (%d)n", GetLastError());      
        return FALSE;     
    }     
          
    // 显示状态     
    printf("nStatus of Sample_Srv: n");     
    printf("  Service Type: 0x%xn", ssStatus.dwServiceType);      
    printf("  Current State: 0x%xn", ssStatus.dwCurrentState);      
    printf("  Controls Accepted: 0x%xn",      
        ssStatus.dwControlsAccepted);      
    printf("  Exit Code: %dn", ssStatus.dwWin32ExitCode);      
    printf("  Service Specific Exit Code: %dn",      
        ssStatus.dwServiceSpecificExitCode);      
    printf("  Check Point: %dn", ssStatus.dwCheckPoint);      
    printf("  Wait Hint: %dn", ssStatus.dwWaitHint);      
          
    return TRUE;      
}

猜你喜欢

转载自jacky-dai.iteye.com/blog/1836811