如何将VC做的应用程序改为一个服务程序

不要用对话框程序,直接写控制台程序(MFC),在程序中加入NTservice类。在main函数中加入如下最后的代码,就可以安装、卸载、启动和停止服务了。

NTservice.CPP 文件

/*********************************************************************
** 文件名: 后台服务器操作;
** 描述:   主函数名:Run();
** 功能:   启动服务线程,接收服务管理器控制消息.
**--------------------------------------------------------------------
*********************************************************************/
//
//
// NTService.cpp: implementation of the CNTService class.//
//
//

#include "stdafx.h"
#include "Resource.h"
#include "NTService.h"

DWORD CNTService::dwThreadId;
LPSTR CNTService::m_lpServiceName;        //服务程序内部名称,名字不能有空格
LPSTR CNTService::m_lpServiceDisplayName; //SERVICE程序在管理器中的显示名称,任意字符
TCHAR CNTService::m_lpServicePathName[512];    //SERVICE程序的EXE文件路径
CNTService * CNTService::m_pService;
SERVICE_STATUS CNTService::m_ssServiceStatus ;//SERVICE程序的状态struct
SERVICE_STATUS_HANDLE CNTService::m_sshServiceStatusHandle ;//SERVICE程序状态的HANDLE

//
// Construction/Destruction
//

CNTService::CNTService()
{

    GetModuleFileName(NULL, m_lpServicePathName, 512); //取当前执行文件路径
    
    m_lpServiceName           = "Service";  //服务名称          
    m_lpServiceDisplayName    = "服务器";  //显示的名称
    m_pService = this ;
    m_ssServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    m_ssServiceStatus.dwServiceSpecificExitCode = 0 ;
}

CNTService::~CNTService()
{

}

/*********************************************************************
** 将执行文件安装进NT SERVICE管理器内
*********************************************************************/
BOOL CNTService::InstallService() 
{
    SC_HANDLE schSCManager;      //打开SCM用的句柄
    SC_HANDLE schService;        //建立SERVICE用的句柄

    schSCManager = OpenSCManager(        //调用打开SERVICE管理器API
NULL,        //机器名称,设置NULL为本地机器
NULL,        //数据库名称,NULL为缺省数据库
SC_MANAGER_CREATE_SERVICE //或 SC_MANAGER_ALL_ACCESS
);                      //希望打开的操作权限,详见MSDN

    if( schSCManager )        // 如果打开SERVICE管理器成功
    {
        schService = CreateService(        //调用建立SERVICE的API
            schSCManager,                //SERVICE管理器数据库的句柄
            TEXT(m_lpServiceName),            //服务名称
            TEXT(m_lpServiceDisplayName),        //显示的名称
            SERVICE_ALL_ACCESS,            //希望得到的运行权限
            SERVICE_WIN32_OWN_PROCESS,    //SERVICE的类型
            SERVICE_AUTO_START,            //启动的方式
            SERVICE_ERROR_NORMAL,        //错误控制类型
            TEXT(m_lpServicePathName),        //可执行文件的路径名
            NULL,        //一组服务装入时的顺序
            NULL,        //检查人标记
            _T("RPCSS\0"),        //从属
            NULL,        //本地USER名
            NULL);        //密码

        if( schService )    //如果建立SERVICE成功
        {
//修改描述
ChangeServiceConfig2(schService,
            CloseServiceHandle(schService);        //释放SERVICE句柄,准备退出
        }else
        {
            return FALSE ; //建立SERVICE失败返回
        }
        CloseServiceHandle(schSCManager);        //释放SERVICE管理器句柄
    }else
    {
        return FALSE; //打开管理器失败返回
    }
    return TRUE; //一切正常返回 
}

/*********************************************************************
** 将SERVICE程序从SCM管理器中移走
*********************************************************************/
BOOL CNTService::RemoveService() 
{
    SC_HANDLE        schSCManager;    //打开SCM用的句柄
    SC_HANDLE        schService;        //建立SERVICE用的句柄

    schSCManager = OpenSCManager(        //调用打开SERVICE管理器API
NULL,        //机器名称,设置NULL为本地机器
NULL,        //数据库名称,NULL为缺省数据库
SC_MANAGER_ALL_ACCESS //希望打开的操作权限,详见MSDN
);                      

    if( schSCManager )        // 如果打开SERVICE管理器成功
    {
        schService = OpenService(    //获取SERVICE控制句柄的API
            schSCManager,            //SCM管理器句柄
            m_lpServiceName,        //SERVICE内部名称,控制名称
            SERVICE_ALL_ACCESS);    //打开的权限,删除就要全部权限

        if( schService )    //如果获取SERVICE句柄成功
        {
            if( ControlService(schService, SERVICE_CONTROL_STOP, &m_ssServiceStatus) )
            {   //直接向SERVICE发STOP命令,如果能够执行到这里,说明SERVICE正运行
                //那就需要停止程序执行后才能删除
                Sleep(3000) ; //等3秒使系统有时间执行STOP命令
                while( QueryServiceStatus(schService, &m_ssServiceStatus) )
                {                                            //循环检查SERVICE状态
                    if(m_ssServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
                    {                    //如果SERVICE还正在执行(PENDING)停止任务
                        Sleep(1000) ;    //那就等1秒钟后再检查SERVICE是否停止OK
                    }else break ;//STOP命令处理完毕,跳出循环
                }//循环检查SERVICE状态结束
                if(m_ssServiceStatus.dwCurrentState != SERVICE_STOPPED)
                {                    //如果SERVICE接受STOP命令后还没有STOPPED
                    return FALSE;    //那就返回FALSE报错,用GetLastError取错误代码
                }
            }
            //删除指令在这里
            if(! DeleteService(schService) )    //删除这个SERVICE
            {
                CloseServiceHandle(schService);        //释放SERVICE控制句柄
                return FALSE;    //如果删除失败返回
            }else CloseServiceHandle(schService);    //释放SERVICE控制句柄
        }else //取SERVICE句柄不成功
        {
            return FALSE; //获取SERVICE句柄失败,或没有找到SERVICE名字返回
        }
        CloseServiceHandle(schSCManager); //释放SCM管理器句柄
    }else    //打开管理器不成功
    {    
        return FALSE; //打开管理器失败返回
    }
    return TRUE; //正常删除返回
}

/*********************************************************************
** 从系统中取最后一次错误代码,并转换成字符串返回
*********************************************************************/
LPTSTR CNTService::GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ) 
{
    DWORD dwRet;
    LPTSTR lpszTemp = NULL;

    dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
GetLastError(),
LANG_NEUTRAL,
(LPTSTR)&lpszTemp,
0,
NULL );

    // supplied buffer is not long enough
    if(!dwRet||((long)dwSize<(long)dwRet+14))
lpszBuf[0] = TEXT('\0');
    else{
        lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');  //remove cr and newline character
        _stprintf( lpszBuf, TEXT("%s (%ld)"), lpszTemp, GetLastError() );
    }

    if ( lpszTemp )
        LocalFree((HLOCAL) lpszTemp );

    return lpszBuf;
}

/*********************************************************************
** 执行缺省的服务控制Dispatcher,服务开始前执行的缺省注册
*********************************************************************/
BOOL CNTService::StartDispatch() 
{
    SERVICE_TABLE_ENTRY DispatchTable[] = 
    { 
        {m_lpServiceName,ServiceMain},
        {NULL, NULL}            
    };                            //如果只有一个SERVICE就定义成2,如果有
//二个以上的SERVICE在一个文件里,这个
//表就要定义成3维或更多
    m_bService = TRUE ;
    if( !StartServiceCtrlDispatcher(DispatchTable))
        return FALSE;
    return TRUE;
}

/*********************************************************************
** 服务程序开始的主程序,主要的初始化及主体服务程序均在此,
** 此函数内须处理STOP、PAUSE、CONTINUE等事件
*********************************************************************/
void WINAPI CNTService::ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
    m_sshServiceStatusHandle = 
        RegisterServiceCtrlHandler(m_lpServiceName, ServiceHandle);
    if(!m_sshServiceStatusHandle){
        AddToMessageLog("RegisterServiceCtrlHandler Error!");
        return ;
    }

    if(SetSCMStatus(SERVICE_START_PENDING, NO_ERROR,3000)){
        m_pService->dwThreadId = GetCurrentThreadId() ;
        if(m_pService->Initialize()){
            m_pService->Run();
            m_pService->UnInitialize();
        }
    }
    SetSCMStatus(SERVICE_STOPPED, NO_ERROR, 0);
}

/*********************************************************************
** 此函数接受系统发来的STOP、PAUSE,并做出相应处理发给Service_Main,
** 每一个指令执行后需报告当前状态给SCM管理器
*********************************************************************/
void WINAPI CNTService::ServiceHandle(DWORD dwControl)
{
    switch(dwControl){
    case SERVICE_CONTROL_STOP:
        m_pService->Stop() ;
        SetSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 3000);
        PostThreadMessage(m_pService->dwThreadId, WM_QUIT, 0, 0 ) ;
        break;
    case SERVICE_CONTROL_PAUSE:
        m_pService->Pause() ;
        break;
    case SERVICE_CONTROL_CONTINUE:
        m_pService->Continue() ;
        break;
    case SERVICE_CONTROL_INTERROGATE:
        break;
    default:
        break;
    }
}

/*********************************************************************
** 将成功信息加进系统EVENT管理器中
*********************************************************************/
void CNTService::AddToMessageLog(LPCTSTR lpszMsg)
{
    TCHAR    szMsg[256];
    HANDLE   hEventSource;
    LPCTSTR  lpszStrings[2];

    if(!m_pService->m_bService){
        printf("%s", lpszMsg) ;
        return ;
    }

    // Use event logging to log the error.
    
    hEventSource = RegisterEventSource(0, m_lpServiceName);

_stprintf(szMsg, TEXT("\n%s 提示信息: %d"), m_lpServiceDisplayName, GetLastError());
lpszStrings[0] = szMsg;
    lpszStrings[1] = lpszMsg;

    if(hEventSource != NULL){

        ReportEvent(hEventSource,  // handle of event source
EVENTLOG_SUCCESS,      // event type
0,                     // event category
0,                     // event ID
NULL,                  // current user's SID
2,                     // number of strings in lpszStrings
0,                     // no bytes of raw data
lpszStrings,           // array of error strings
NULL);                 // no raw data
        (VOID) DeregisterEventSource(hEventSource);
    }
}

/*********************************************************************
** 将错误信息加进系统EVENT管理器中;
*********************************************************************/
void CNTService::AddToErrorMessageLog(LPCTSTR lpszMsg)
{
    TCHAR    szMsg[256];
    HANDLE   hEventSource;
    LPCTSTR  lpszStrings[2];

    if(!m_pService->m_bService){
        printf("%s", lpszMsg) ;
        return ;
    }
    // Use event logging to log the error.
    
    hEventSource = RegisterEventSource(0, m_lpServiceName);

    _stprintf(szMsg, TEXT("\n%s 提示信息: %d"), m_lpServiceDisplayName, GetLastError());
    lpszStrings[0] = szMsg;
    lpszStrings[1] = lpszMsg;

    if(hEventSource != NULL){

        ReportEvent(hEventSource, // handle of event source
EVENTLOG_ERROR_TYPE, // event type
0, // event category
0, // event ID
NULL, // current user's SID
2, // number of strings in lpszStrings
0, // no bytes of raw data
lpszStrings, // array of error strings
NULL); // no raw data
        (VOID) DeregisterEventSource(hEventSource);
    }

}

/*********************************************************************
** 将警告信息加进系统EVENT管理器中;
*********************************************************************/
void CNTService::AddToWarningMessageLog(LPCTSTR lpszMsg)
{
    TCHAR    szMsg[256];
    HANDLE   hEventSource;
    LPCTSTR  lpszStrings[2];

    if(!m_pService->m_bService){
        printf("%s", lpszMsg) ;
        return ;
    }

    // Use event logging to log the error.
    
    hEventSource = RegisterEventSource(0, m_lpServiceName);

    _stprintf(szMsg, TEXT("\n%s 提示信息: %d"), m_lpServiceDisplayName, GetLastError());
    lpszStrings[0] = szMsg;
    lpszStrings[1] = lpszMsg;

    if(hEventSource != NULL){

        ReportEvent(hEventSource,    // handle of event source
EVENTLOG_WARNING_TYPE,   // event type
0,                       // event category
0,                       // event ID
NULL,                    // current user's SID
2,                       // number of strings in lpszStrings
0,                       // no bytes of raw data
lpszStrings,             // array of error strings
NULL);                   // no raw data
        (VOID) DeregisterEventSource(hEventSource);
    }
}

/*********************************************************************
** 将程序当前状态报告给SCM管理器,使管理器的显示与当前程序同步;
*********************************************************************/
BOOL CNTService::SetSCMStatus(DWORD dwCurrentState,
  DWORD dwWin32ExitCode,
  DWORD dwWaitHint)
{
    static DWORD dwCheckPoint = 1;
    BOOL fResult = TRUE;

    if (dwCurrentState == SERVICE_START_PENDING)
        m_ssServiceStatus.dwControlsAccepted = 0;
    else
        m_ssServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

    m_ssServiceStatus.dwCurrentState = dwCurrentState;
    m_ssServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
    m_ssServiceStatus.dwWaitHint = dwWaitHint;

    if ( ( dwCurrentState == SERVICE_RUNNING ) ||
        ( dwCurrentState == SERVICE_STOPPED ) )
        m_ssServiceStatus.dwCheckPoint = 0;
    else
        m_ssServiceStatus.dwCheckPoint = dwCheckPoint++;


    // Report the status of the service to the service control manager.
    //
    if (!(fResult = SetServiceStatus( m_sshServiceStatusHandle, &m_ssServiceStatus))){
        AddToMessageLog(TEXT("SetServiceStatus"));
    }
    return fResult;
}

/*********************************************************************
** 
*********************************************************************/
BOOL CNTService::Initialize()
{
    if(!SetSCMStatus(SERVICE_RUNNING, NO_ERROR, 0))
        return FALSE ;

return TRUE;
}

/*********************************************************************
** 
*********************************************************************/
void CNTService::UnInitialize()
{

}

/*********************************************************************
** 
*********************************************************************/
void CNTService::Stop()
{

}

/*********************************************************************
** 
*********************************************************************/
void CNTService::Pause()
{

}

/*********************************************************************
** 
*********************************************************************/
void CNTService::Continue()
{

}

/*********************************************************************
** 主函数;
*********************************************************************/
void CNTService::Run() 
{
//在此调用服务的实际程序
//进入消息循环;
MSG msg;
while(GetMessage(&msg,0,0,0)){
AddToMessageLog(_T("收到消息"));
DispatchMessage(&msg);
}
}


NTservice.h文件
// NTService.h: interface for the CNTService class.
//
//

#if !defined(AFX_NTSERVICE_H__4EF874F0_2934_11D3_AFC2_5254ABDD3C8E__INCLUDED_)
#define AFX_NTSERVICE_H__4EF874F0_2934_11D3_AFC2_5254ABDD3C8E__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <windows.h>
#include <winsvc.h>
#include <stdio.h>
#include <tchar.h>

class CNTService  
{
public:
    BOOL m_bService;
    virtual void Continue();
    virtual void Pause();
    virtual void Stop();
    virtual void UnInitialize();
    virtual void Run();
    virtual BOOL Initialize();
    
    static CNTService * m_pService;
    static void WINAPI ServiceHandle(DWORD dwControl);
    static void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
    static BOOL SetSCMStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
    static void AddToMessageLog(LPCTSTR lpszMsg);
    static void AddToErrorMessageLog(LPCTSTR lpszMsg) ;
static void AddToWarningMessageLog(LPCTSTR lpszMsg);

    BOOL StartDispatch();
    BOOL RemoveService();    //将服务程序从SCM管理器中删除掉
    BOOL InstallService();    //将服务程序安装进SCM管理器中

    LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize);

    CNTService();            //构造
    virtual ~CNTService();    //析构

    static LPSTR m_lpServiceName;        //服务程序内部名称,名字不能有空格
    static LPSTR m_lpServiceDisplayName; //SERVICE程序在管理器中的显示名称,任意字符
private:
    static DWORD dwThreadId ;
    static TCHAR m_lpServicePathName[512];    //SERVICE程序的EXE文件路径
    static SERVICE_STATUS m_ssServiceStatus ;//SERVICE程序的状态struct
    static SERVICE_STATUS_HANDLE m_sshServiceStatusHandle ;//SERVICE程序状态的HANDLE
};

#endif // !defined(AFX_NTSERVICE_H__4EF874F0_2934_11D3_AFC2_5254ABDD3C8E__INCLUDED_)

/*********************************************************************
*********************************************************************
*********************************************************************
*********************************************************************
*********************************************************************/

main程序:
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
CNTService cService;

    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        { TEXT(cService.m_lpServiceName), (LPSERVICE_MAIN_FUNCTION)cService.ServiceMain},
        { NULL, NULL }
    };
// initialize MFC and print and error on failure
if(!AfxWinInit(::GetModuleHandle(NULL),NULL,::GetCommandLine(),0)){
cerr << _T("程序启动错误!") << endl;
nRetCode=1;
}else{
if((argc>1)&&((*argv[1]=='-')||(*argv[1]=='/'))){
if(_stricmp("install",argv[1]+1)==0){
cout << _T("正在安装服务器...") << endl;
if(cService.InstallService())
cout << _T("服务器安装成功!") << endl;
else
cout << _T("服务器安装失败!") << endl;
}else if(_stricmp("remove",argv[1]+1)==0){
cout << _T("正在删除服务器...") << endl;
if(cService.RemoveService())
cout << _T("服务器删除成功!") << endl;
else
cout << _T("服务器删除失败!") << endl;
}
}else{
cout << _T("-install 安装服务器") << endl;
cout << _T("-remove 卸载服务器") << endl;
cout << _T("正在启动服务器,请稍候...") << endl;
if(!cService.StartDispatch())
cService.AddToErrorMessageLog(TEXT("服务器启动失败!"));
}
    }
return nRetCode;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值