您的位置:首页 > 其它

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

2014-10-19 23:04 316 查看
不要用对话框程序,直接写控制台程序(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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: