基于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 %d\n", 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 %ld\n",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 %ld\n", 
				status); 
		}  
		SvcDebugOut(" [SPLSRV_SERVICE] Leaving SplSrvService \n",0); 
		return; 
	case SERVICE_CONTROL_INTERROGATE: 
		// 收到此请求后发出声响,演示服务控制请求的处理过程,读者可自行修改
		MessageBeep(MB_OK);
		break; 
	default: 
		SvcDebugOut(" [SPLSRV_SERVICE] Unrecognized opcode %ld\n", 
			Opcode); 
	} 
	// 当前状态
	if (!SetServiceStatus (SplSrvServiceStatusHandle,  &SplSrvServiceStatus)) 
	{ 
		status = GetLastError(); 
		SvcDebugOut(" [SPLSRV_SERVICE] SetServiceStatus error %ld\n", 
			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 succeeded\n"); 
		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 succeeded\n"); 
	// 关闭句柄
	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 Stoped\n"); 
	} 
	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: %d\n", ssStatus.dwCurrentState); 
		printf("  Exit Code: %d\n", ssStatus.dwWin32ExitCode); 
		printf("  Service Specific Exit Code: %d\n", 
			ssStatus.dwServiceSpecificExitCode); 
		printf("  Check Point: %d\n", ssStatus.dwCheckPoint); 
		printf("  Wait Hint: %d\n", 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%x\n", ssStatus.dwServiceType); 
	printf("  Current State: 0x%x\n", ssStatus.dwCurrentState); 
	printf("  Controls Accepted: 0x%x\n", 
		ssStatus.dwControlsAccepted); 
	printf("  Exit Code: %d\n", ssStatus.dwWin32ExitCode); 
	printf("  Service Specific Exit Code: %d\n", 
		ssStatus.dwServiceSpecificExitCode); 
	printf("  Check Point: %d\n", ssStatus.dwCheckPoint); 
	printf("  Wait Hint: %d\n", ssStatus.dwWaitHint); 

	return TRUE; 
}


 


 

你可能感兴趣的:(编程,C++,windows,service,代码分析,winapi)