Windows下服务编程及启动

xingyun86 2018-5-10 2659

某些时候,我们需要启动服务提升权限及自启动完成。下面就是一个服务程序的一个基本例子。

头文件

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <strsafe.h>
#include <Wtsapi32.h>
#include <Userenv.h>
#include <TlHelp32.h>
#pragma comment(lib, "Wtsapi32.lib")
#pragma comment(lib, "Userenv.lib")
// TODO: reference additional headers your program requires here
// The following are message definitions.
//
//  Values are 32 bit values layed out as follows:
//
//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
//  +---+-+-+-----------------------+-------------------------------+
//  |Sev|C|R|     Facility          |               Code            |
//  +---+-+-+-----------------------+-------------------------------+
//
//  where
//
//      Sev - is the severity code
//
//          00 - Success
//          01 - Informational
//          10 - Warning
//          11 - Error
//
//      C - is the Customer code flag
//
//      R - is a reserved bit
//
//      Facility - is the facility code
//
//      Code - is the facility's status code
//
//
// Define the facility codes
//
#define FACILITY_SYSTEM                  0x0
#define FACILITY_STUBS                   0x3
#define FACILITY_RUNTIME                 0x2
#define FACILITY_IO_ERROR_CODE           0x4
//
// Define the severity codes
//
#define STATUS_SEVERITY_WARNING          0x2
#define STATUS_SEVERITY_SUCCESS          0x0
#define STATUS_SEVERITY_INFORMATIONAL    0x1
#define STATUS_SEVERITY_ERROR            0x3
//
// MessageId: SVC_ERROR
//
// MessageText:
//
//  An error has occurred (%2).
//  
//
#define SVC_ERROR                        ((DWORD)0xC0020001L)
#include <map>
#include <string>
#if !defined(_UNICODE) && !defined(UNICODE)
#define TSTRING std::string
#else
#define TSTRING std::wstring
#endif
__inline static BOOL CreateAdvanceProcess(
	LPCTSTR lpApplicationName,
	LPTSTR lpCommandLine,
	DWORD dwCreateFlags,
	LPCTSTR lpCurrentDirectory = NULL,
	LPSTARTUPINFO lpStartupInfo = NULL,
	LPPROCESS_INFORMATION lpProcessInformation = NULL,
	LPVOID lpEnvironment = NULL,
	LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL,
	LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL,
	BOOL bInheritHandles = FALSE)
{
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	LPSTARTUPINFO lpsi = &si;
	LPPROCESS_INFORMATION lppi = &pi;
	if (lpStartupInfo)
	{
		lpsi = lpStartupInfo;
	}
	if (lpProcessInformation)
	{
		lppi = lpProcessInformation;
	}
	return CreateProcess(
		lpApplicationName,
		lpCommandLine,
		lpProcessAttributes,
		lpThreadAttributes,
		bInheritHandles,
		dwCreateFlags,
		lpEnvironment,
		lpCurrentDirectory,
		lpsi,
		lppi
		);
}
__inline static BOOL CreateAdvanceProcessAsUser(
	LPCTSTR lpApplicationName,
	LPTSTR lpCommandLine,
	DWORD dwCreateFlags,
	LPCTSTR lpCurrentDirectory = NULL,
	LPSTARTUPINFO lpStartupInfo = NULL,
	LPPROCESS_INFORMATION lpProcessInformation = NULL,
	LPVOID lpEnvironment = NULL,
	LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL,
	LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL,
	BOOL bInheritHandles = FALSE,
	HANDLE hToken = NULL)
{
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	LPSTARTUPINFO lpsi = &si;
	LPPROCESS_INFORMATION lppi = &pi;
	if (lpStartupInfo)
	{
		lpsi = lpStartupInfo;
	}
	if (lpProcessInformation)
	{
		lppi = lpProcessInformation;
	}
	return CreateProcessAsUser(
		hToken,
		lpApplicationName,
		lpCommandLine,
		lpProcessAttributes,
		lpThreadAttributes,
		bInheritHandles,
		dwCreateFlags,
		lpEnvironment,
		lpCurrentDirectory,
		lpsi,
		lppi
		);
}
//获取进程用户函数:
__inline static BOOL GetProcessUserName(TSTRING & strUser, DWORD dwID) // 进程ID 
{
	HANDLE hToken = NULL;
	BOOL bResult = FALSE;
	DWORD dwSize = 0;
	TCHAR szUserName[256] = { 0 };
	TCHAR szDomain[256] = { 0 };
	DWORD dwDomainSize = 256;
	DWORD dwNameSize = 256;
	SID_NAME_USE    SNU;
	PTOKEN_USER pTokenUser = NULL;
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwID);
	strUser = _T("SYSTEM");
	if (hProcess == NULL)
	{
		switch (GetLastError())
		{
		case ERROR_ACCESS_DENIED:
			strUser = _T("SYSTEM");
			break;
		default:
			strUser = _T("SYSTEM");
			break;
		}
		return bResult;
	}
	__try
	{
		if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
		{
			bResult = FALSE;
			__leave;
		}
		if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
		{
			if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
			{
				bResult = FALSE;
				__leave;
			}
		}
		pTokenUser = NULL;
		pTokenUser = (PTOKEN_USER)malloc(dwSize);
		if (pTokenUser == NULL)
		{
			bResult = FALSE;
			__leave;
		}
		if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
		{
			bResult = FALSE;
			__leave;
		}
		if (LookupAccountSid(NULL, pTokenUser->User.Sid, szUserName, &dwNameSize, szDomain, &dwDomainSize, &SNU) != 0)
		{
			strUser = szUserName;
			if (pTokenUser != NULL)
			{
				free(pTokenUser);
				pTokenUser = NULL;
			}
			return TRUE;
		}
	}
	__finally
	{
		if (pTokenUser != NULL)
			free(pTokenUser);
	}
	return FALSE;
}
///////////////////////////////////////////////////////////////////////
//获取进程映像名称
//Windows 2000		= GetModuleFileName()
//Windows XP x32	= GetProcessImageFileName()
//Windows XP x64	= GetProcessImageFileName()
//Windows Vista		= QueryFullProcessImageName()
//Windows 7			= QueryFullProcessImageName()
//Windows 8			= QueryFullProcessImageName()
//Windows 8.1		= QueryFullProcessImageName()
//Windows 10		= QueryFullProcessImageName()
///////////////////////////////////////////////////////////////////////
__inline static BOOL EnumModules_R3(std::map<DWORD, MODULEENTRY32> * pmemap, DWORD dwPID)
{
	BOOL bRet = FALSE;
	MODULEENTRY32 me = { 0 };
	HANDLE hSnapModule = INVALID_HANDLE_VALUE;
	// Take a snapshot of all modules in the specified process.
	hSnapModule = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
	if (hSnapModule == INVALID_HANDLE_VALUE)
	{
		goto __LEAVE_CLEAN__;
	}
	// Set the size of the structure before using it.
	me.dwSize = sizeof(MODULEENTRY32);
	// Retrieve information about the first module,
	// and exit if unsuccessful
	if (!Module32First(hSnapModule, &me))
	{
		goto __LEAVE_CLEAN__;
	}
	// Now walk the module list of the process,
	// and display information about each module
	do
	{
		pmemap->insert(std::map<DWORD, MODULEENTRY32>::value_type(me.th32ModuleID, me));
	} while (Module32Next(hSnapModule, &me));
__LEAVE_CLEAN__:
	//关闭句柄
	CloseHandle(hSnapModule);
	hSnapModule = NULL;
	return bRet;
}
__inline static BOOL EnumModules32_R3(std::map<DWORD, MODULEENTRY32> * pmemap, DWORD dwPID)
{
	BOOL bRet = FALSE;
	MODULEENTRY32 me = { 0 };
	HANDLE hSnapModule = INVALID_HANDLE_VALUE;
	// Take a snapshot of all modules in the specified process.
	hSnapModule = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32, dwPID);
	if (hSnapModule == INVALID_HANDLE_VALUE)
	{
		goto __LEAVE_CLEAN__;
	}
	// Set the size of the structure before using it.
	me.dwSize = sizeof(MODULEENTRY32);
	// Retrieve information about the first module,
	// and exit if unsuccessful
	if (!Module32First(hSnapModule, &me))
	{
		goto __LEAVE_CLEAN__;
	}
	// Now walk the module list of the process,
	// and display information about each module
	do
	{
		pmemap->insert(std::map<DWORD, MODULEENTRY32>::value_type(me.th32ModuleID, me));
	} while (Module32Next(hSnapModule, &me));
__LEAVE_CLEAN__:
	//关闭句柄
	CloseHandle(hSnapModule);
	hSnapModule = NULL;
	return bRet;
}
__inline static BOOL EnumProcess_R3(std::map<DWORD, PROCESSENTRY32> * ppemap)
{
	BOOL bRet = FALSE;
	PROCESSENTRY32 pe = { 0 };
	HANDLE hSnapProcess = INVALID_HANDLE_VALUE;
	//创建快照
	hSnapProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnapProcess == INVALID_HANDLE_VALUE)
	{
		goto __LEAVE_CLEAN__;
	}
	pe.dwSize = sizeof(PROCESSENTRY32);
	//遍历进程	
	bRet = Process32First(hSnapProcess, &pe);
	if (!bRet)
	{
		goto __LEAVE_CLEAN__;
	}
	do
	{
		ppemap->insert(std::map<DWORD, PROCESSENTRY32>::value_type(pe.th32ProcessID, pe));
	} while (Process32Next(hSnapProcess, &pe));
__LEAVE_CLEAN__:
	//关闭句柄
	CloseHandle(hSnapProcess);
	hSnapProcess = NULL;
	return bRet;
}
__inline static BOOL EnumThread_R3(std::map<DWORD, THREADENTRY32> * ptemap, DWORD dwPID)
{
	BOOL bRet = FALSE;
	THREADENTRY32 te = { 0 };
	HANDLE hSnapThread = INVALID_HANDLE_VALUE;
	//创建快照
	hSnapThread = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwPID);
	if (hSnapThread == INVALID_HANDLE_VALUE)
	{
		goto __LEAVE_CLEAN__;
	}
	te.dwSize = sizeof(THREADENTRY32);
	//遍历进程	
	bRet = Thread32First(hSnapThread, &te);
	if (!bRet)
	{
		goto __LEAVE_CLEAN__;
	}
	do
	{
		ptemap->insert(std::map<DWORD, THREADENTRY32>::value_type(te.th32ThreadID, te));
	} while (Thread32Next(hSnapThread, &te));
__LEAVE_CLEAN__:
	//关闭句柄
	CloseHandle(hSnapThread);
	hSnapThread = NULL;
	return bRet;
}
__inline static BOOL EnumHeapList_R3(std::map<ULONG_PTR, HEAPLIST32> * phlmap, DWORD dwPID)
{
	BOOL bRet = FALSE;
	HEAPLIST32 hl = { 0 };
	HANDLE hSnapHeapList = INVALID_HANDLE_VALUE;
	//创建快照
	hSnapHeapList = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, dwPID);
	if (hSnapHeapList == INVALID_HANDLE_VALUE)
	{
		goto __LEAVE_CLEAN__;
	}
	hl.dwSize = sizeof(HEAPLIST32);
	//遍历进程	
	bRet = Heap32ListFirst(hSnapHeapList, &hl);
	if (!bRet)
	{
		goto __LEAVE_CLEAN__;
	}
	do
	{
		phlmap->insert(std::map<ULONG_PTR, HEAPLIST32>::value_type(hl.th32HeapID, hl));
	} while (Heap32ListNext(hSnapHeapList, &hl));
__LEAVE_CLEAN__:
	//关闭句柄
	CloseHandle(hSnapHeapList);
	hSnapHeapList = NULL;
	return bRet;
}
__inline static	DWORD GetProcessIdByProcessName(const _TCHAR * ptProcessName)
{
	DWORD dwPID = 0;
	_TCHAR tzProcessName[MAX_PATH] = { 0 };
	std::map<DWORD, PROCESSENTRY32> pemap;
	std::map<DWORD, PROCESSENTRY32>::iterator itEnd;
	std::map<DWORD, PROCESSENTRY32>::iterator itIdx;
	lstrcpy(tzProcessName, ptProcessName);
	EnumProcess_R3(&pemap);
	itEnd = pemap.end();
	itIdx = pemap.begin();
	for (; itIdx != itEnd; itIdx++)
	{
		if (!_tcsicmp(itIdx->second.szExeFile, tzProcessName))
		{
			dwPID = itIdx->second.th32ProcessID;
			break;
		}
	}
	return dwPID;
}
__inline static BOOL GetProcessFileNameByProcessId(const DWORD dwProcessId, TSTRING & cstrPath)
{
	HANDLE hProcess = NULL;
	BOOL bSuccess = FALSE;
	// 由于进程权限问题,有些进程是无法被OpenProcess的,如果将调用进程的权限
	// 提到“调试”权限,则可能可以打开更多的进程
	hProcess = OpenProcess(
		PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
		FALSE, dwProcessId);
	if (hProcess)
	{
		std::map<DWORD, MODULEENTRY32> memap;
		EnumModules_R3(&memap, dwProcessId);
	}
	// 释放句柄
	if (NULL != hProcess)
	{
		CloseHandle(hProcess);
		hProcess = NULL;
	}
	return bSuccess;
}
__inline static HANDLE InitProcessHandle(DWORD dwPID)
{
	// Open process
	return ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, dwPID);
}
__inline static HANDLE InitProcessHandle(const _TCHAR * ptProcessName)
{
	DWORD dwPID = 0;
	dwPID = GetProcessIdByProcessName(ptProcessName);
	// Open process
	return ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, dwPID);
}
__inline static void ExitProcessHandle(HANDLE * pHandle)
{
	if (pHandle && (*pHandle))
	{
		CloseHandle((*pHandle));
		(*pHandle) = NULL;
	}
}
__inline static BOOL EnablePriv()
{
	HANDLE hToken;
	if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
		//用上面这个办法,在执行ExitWindowsEX注销的时候可以,但是重启,关机就不行了,改成以下可以解决
		if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
		{
			TOKEN_PRIVILEGES tkp;
			LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);//修改进程权限
			tkp.PrivilegeCount = 1;
			tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
			AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL);//通知系统修改进程权限
			return((GetLastError() == ERROR_SUCCESS));
		}
	return TRUE;
}

源文件

// serviceapp.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#pragma comment(lib, "advapi32.lib")
#define SVCNAME TEXT("SvcName")
SERVICE_STATUS          gSvcStatus;
SERVICE_STATUS_HANDLE   gSvcStatusHandle;
HANDLE                  ghSvcStopEvent = NULL;
VOID SvcInstall(void);
VOID WINAPI SvcCtrlHandler(DWORD);
VOID WINAPI SvcMain(DWORD, LPTSTR *);
VOID ReportSvcStatus(DWORD, DWORD, DWORD);
VOID SvcInit(DWORD, LPTSTR *);
VOID SvcReportEvent(LPTSTR);
void MyTest()
{
	EnablePriv();
	DWORD dwSessionId = WTSGetActiveConsoleSessionId();
	HANDLE hToken = NULL;
	HANDLE hUserTokenDup = NULL;
	HANDLE hSystemHandle = InitProcessHandle(_T("winlogon.exe"));
	_TCHAR tszCmdLine[MAX_PATH] = { 0 };
	FILE * pFile = _tfopen(_T("d:\\svc.log"), _T("wb"));
	if (sizeof(_TCHAR) > sizeof(BYTE))
	{
		fwrite("\xFF\xFE", sizeof(_TCHAR), sizeof(BYTE), pFile);
	}
	//WinExec("c:\\windows\\notepad.exe", SW_SHOW);
	dwSessionId = WTSGetActiveConsoleSessionId();
	if (dwSessionId)
	{
		WTSQueryUserToken(dwSessionId, &hToken);
		_ftprintf(pFile, _T("WTSQueryUserToken hToken=%ld(0x%08X)\r\n"), hToken, hToken);
		fflush(pFile);
	}
	if (hSystemHandle)
	{
		OpenProcessToken(hSystemHandle, TOKEN_ALL_ACCESS, &hToken);
		ExitProcessHandle(&hSystemHandle);
		_ftprintf(pFile, _T("OpenProcessToken hToken=%ld(0x%08X)\r\n"), hToken, hToken);
		fflush(pFile);
	}
	if (hToken)
	{
		SECURITY_ATTRIBUTES sa = { 0 };
		sa.nLength = sizeof(sa);
		DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, &sa, SECURITY_IMPERSONATION_LEVEL::SecurityIdentification, TOKEN_TYPE::TokenPrimary, &hUserTokenDup);
		if (hUserTokenDup)
		{
			LPVOID lpEnv = NULL;
			CreateEnvironmentBlock(&lpEnv, hUserTokenDup, FALSE);
			if (lpEnv)
			{
				STARTUPINFO sia = { 0 };
				GetStartupInfo(&sia);
				if (pFile)
				{
					_ftprintf(pFile, _T("sia.lpDesktop=%s\r\n"), sia.lpDesktop);
					fflush(pFile);
				}
				STARTUPINFO si = { 0 };
				si.cb = sizeof(si);
				si.lpDesktop = _T("WinSta0\\Default");
				FILE * pf = fopen("D:\\appcmd.txt", "rb");
				if (pf)
				{
					_TCHAR tzAppName[MAX_PATH] = { 0 };
					_TCHAR tzCmdLine[MAX_PATH] = { 0 };
					_ftscanf(pf, _T("%[^|]|%[^|]"), tzAppName, tzCmdLine);
					if (pFile)
					{
						_ftprintf(pFile, _T("read %s=%s\r\n"), tzAppName, tzCmdLine);
						fflush(pFile);
					}
					CreateAdvanceProcessAsUser(
						tzAppName,
						tzCmdLine,
						NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
						0,
						&si,
						0,
						lpEnv, &sa, &sa, FALSE, hUserTokenDup);
					fclose(pf);
				}
				CreateAdvanceProcessAsUser(
					_T("C:\\windows\\system32\\cmd.exe"),
					NULL,
					NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
					0,
					&si,
					0,
					lpEnv, &sa, &sa, FALSE, hUserTokenDup);
				CreateAdvanceProcessAsUser(
					_T("C:\\windows\\notepad.exe"),
					NULL,
					NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
					0,
					&si,
					0,
					lpEnv, &sa, &sa, FALSE, hUserTokenDup);
				DestroyEnvironmentBlock(lpEnv);
			}
			CloseHandle(hUserTokenDup);
		}
		CloseHandle(hToken);
	}
}
//
// Purpose: 
//   Entry point for the process
//
// Parameters:
//   None
// 
// Return value:
//   int
//
int _tmain(int argc, _TCHAR* argv[])
{
	STARTUPINFO si = { 0 };
	GetStartupInfo(&si);
	//PROCESS_INFORMATION pi = { 0 };
	//CreateAdvanceProcess(_T("C:\\windows\\notepad.exe"), 0, CREATE_NEW_CONSOLE, 0, &si, &pi);
	// If command-line parameter is "install", install the service. 
	// Otherwise, the service is probably being started by the SCM.
	if (lstrcmpi(argv[1], TEXT("install")) == 0)
	{
		SvcInstall();
		return 0;
	}
	// TO_DO: Add any additional services for the process to this table.
	SERVICE_TABLE_ENTRY DispatchTable[] =
	{
		{ SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
		{ NULL, NULL }
	};
	// This call returns when the service has stopped. 
	// The process should simply terminate when the call returns.
	if (!StartServiceCtrlDispatcher(DispatchTable))
	{
		DWORD dwErr = GetLastError();
		SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
	}
	else
	{
		printf("执行成功\r\n");
	}
	return 0;
}
//
// Purpose: 
//   Installs a service in the SCM database
//
// Parameters:
//   None
// 
// Return value:
//   None
//
VOID SvcInstall()
{
	SC_HANDLE schSCManager;
	SC_HANDLE schService;
	TCHAR szPath[MAX_PATH];
	if (!GetModuleFileName(NULL, szPath, MAX_PATH))
	{
		printf("Cannot install service (%d)\n", GetLastError());
		return;
	}
	// Get a handle to the SCM database. 
	schSCManager = OpenSCManager(
		NULL,                    // local computer
		NULL,                    // ServicesActive database 
		SC_MANAGER_ALL_ACCESS);  // full access rights 
	if (NULL == schSCManager)
	{
		printf("OpenSCManager failed (%d)\n", GetLastError());
		return;
	}
	// Create the service
	schService = CreateService(
		schSCManager,              // SCM database 
		SVCNAME,                   // name of service 
		SVCNAME,                   // service name to display 
		SERVICE_ALL_ACCESS,        // desired access 
		SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, // service type 
		SERVICE_DEMAND_START,      // start type 
		SERVICE_ERROR_NORMAL,      // error control type 
		szPath,                    // path to service's binary 
		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());
		CloseServiceHandle(schSCManager);
		return;
	}
	else printf("Service installed successfully\n");
	CloseServiceHandle(schService);
	CloseServiceHandle(schSCManager);
}
//
// Purpose: 
//   Entry point for the service
//
// Parameters:
//   dwArgc - Number of arguments in the lpszArgv array
//   lpszArgv - Array of strings. The first string is the name of
//     the service and subsequent strings are passed by the process
//     that called the StartService function to start the service.
// 
// Return value:
//   None.
//
VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
	// Register the handler function for the service
	gSvcStatusHandle = RegisterServiceCtrlHandler(
		SVCNAME,
		SvcCtrlHandler);
	if (!gSvcStatusHandle)
	{
		SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
		return;
	}
	// These SERVICE_STATUS members remain as set here
	gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
	gSvcStatus.dwServiceSpecificExitCode = 0;
	// Report initial status to the SCM
	ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
	// Perform service-specific initialization and work.
	SvcInit(dwArgc, lpszArgv);
}
//
// Purpose: 
//   The service code
//
// Parameters:
//   dwArgc - Number of arguments in the lpszArgv array
//   lpszArgv - Array of strings. The first string is the name of
//     the service and subsequent strings are passed by the process
//     that called the StartService function to start the service.
// 
// Return value:
//   None
//
VOID SvcInit(DWORD dwArgc, LPTSTR *lpszArgv)
{
	// TO_DO: Declare and set any required variables.
	//   Be sure to periodically call ReportSvcStatus() with 
	//   SERVICE_START_PENDING. If initialization fails, call
	//   ReportSvcStatus with SERVICE_STOPPED.
	// Create an event. The control handler function, SvcCtrlHandler,
	// signals this event when it receives the stop control code.
	ghSvcStopEvent = CreateEvent(
		NULL,    // default security attributes
		TRUE,    // manual reset event
		FALSE,   // not signaled
		NULL);   // no name
	if (ghSvcStopEvent == NULL)
	{
		ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
		return;
	}
	// Report running status when initialization is complete.
	ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
	// TO_DO: Perform work until service stops.
	MyTest();
	while (1)
	{
		// Check whether to stop the service.
		WaitForSingleObject(ghSvcStopEvent, INFINITE);
		ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
		return;
	}
}
//
// Purpose: 
//   Sets the current service status and reports it to the SCM.
//
// Parameters:
//   dwCurrentState - The current state (see SERVICE_STATUS)
//   dwWin32ExitCode - The system error code
//   dwWaitHint - Estimated time for pending operation, 
//     in milliseconds
// 
// Return value:
//   None
//
VOID ReportSvcStatus(DWORD dwCurrentState,
	DWORD dwWin32ExitCode,
	DWORD dwWaitHint)
{
	static DWORD dwCheckPoint = 1;
	// Fill in the SERVICE_STATUS structure.
	gSvcStatus.dwCurrentState = dwCurrentState;
	gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
	gSvcStatus.dwWaitHint = dwWaitHint;
	if (dwCurrentState == SERVICE_START_PENDING)
		gSvcStatus.dwControlsAccepted = 0;
	else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
	if ((dwCurrentState == SERVICE_RUNNING) ||
		(dwCurrentState == SERVICE_STOPPED))
		gSvcStatus.dwCheckPoint = 0;
	else gSvcStatus.dwCheckPoint = dwCheckPoint++;
	// Report the status of the service to the SCM.
	SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
}
//
// Purpose: 
//   Called by SCM whenever a control code is sent to the service
//   using the ControlService function.
//
// Parameters:
//   dwCtrl - control code
// 
// Return value:
//   None
//
VOID WINAPI SvcCtrlHandler(DWORD dwCtrl)
{
	// Handle the requested control code. 
	switch (dwCtrl)
	{
	case SERVICE_CONTROL_STOP:
		ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
		// Signal the service to stop.
		SetEvent(ghSvcStopEvent);
		ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
		return;
	case SERVICE_CONTROL_INTERROGATE:
		break;
	default:
		break;
	}
}
//
// Purpose: 
//   Logs messages to the event log
//
// Parameters:
//   szFunction - name of function that failed
// 
// Return value:
//   None
//
// Remarks:
//   The service must have an entry in the Application event log.
//
VOID SvcReportEvent(LPTSTR szFunction)
{
	HANDLE hEventSource;
	LPCTSTR lpszStrings[2];
	TCHAR Buffer[80];
	hEventSource = RegisterEventSource(NULL, SVCNAME);
	if (NULL != hEventSource)
	{
		StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());
		lpszStrings[0] = SVCNAME;
		lpszStrings[1] = Buffer;
		ReportEvent(hEventSource,        // event log handle
			EVENTLOG_ERROR_TYPE, // event type
			0,                   // event category
			SVC_ERROR,           // event identifier
			NULL,                // no security identifier
			2,                   // size of lpszStrings array
			0,                   // no binary data
			lpszStrings,         // array of strings
			NULL);               // no binary data
		DeregisterEventSource(hEventSource);
	}
}

使用方法:

编译之后,命令行运行 service.exe install完成服务安装。

sc start SvcName完成服务的启动。也可以通过services.msc将SvcName服务设置为自启动。

×
打赏作者
最新回复 (0)
查看全部
全部楼主
返回