IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]Win8上Service程序及外部App调用此Service

    lincyang发表于 2014-05-08 15:23:38
    love 0

    一.Service

    借助MSDN上Win7 Service的Demo和《用VC++建立Service服务应用程序》,在Win8上经历各种磨难,终于跑起来自己改装的服务程序了。

    原来API基本没变,我所困惑的是Win7上直接运行都没有问题,在Win8上不可以。

    报错:

    OpenSCManager failed w/err 0x00000005

    原来是Win8上权限的问题,也许我自己的Win7一启动就拥有了Admin权限吧。


    下面直接进入正题,我整合了一下代码,共三个文件:main.c,Service.h, Service.cpp。(项目是控制台程序。)

    main.c只是程序的入口,运行时接受参数。

    #pragma region "Includes"
    #include <stdio.h>
    #include <windows.h>
    #include "Service.h"
    #pragma endregion
    
    
    int wmain(int argc, wchar_t* argv[])
    {
    	if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/'))))
    	{
    		if (_wcsicmp(L"install", argv[1] + 1) == 0)
    		{
    			SvcInstall();
    		}
    		else if (_wcsicmp(L"remove", argv[1] + 1) == 0)
    		{
    			SvcUninstall();
    		}
    		else if (_wcsicmp(L"query", argv[1] + 1) == 0)
    		{
    			SvcQueryConfig();
    		}
            else if(_wcsicmp(L"start",argv[1] + 1) == 0)
            {
                SvcStart(); 
            }
            else if(_wcsicmp(L"stop",argv[1] + 1) == 0)
            {
                SvcStopNow(); 
            }
    	}
    	else
    	{
    		_putws(L"Parameters:");
    		_putws(L" -install    to install the service (require admin permission)");
    		_putws(L" -remove     to remove the service (require admin permission)");
    		_putws(L" -query      to query the configuration of the service");
                    _putws(L" -start      to start the service");
                    _putws(L" -stop       to stop the service");
    
    		RunService();
    	}
    
    	return 0;
    }

    代码中已经写的很清楚了,我的项目名称为Win8Service,只要运行Win8Service.exe -install,服务就会被安装。

    注意:cmd必须要用admin启动。win8下做法:WIN+Q键,打开Search panel,输入cmd,右击Command Prompt,选择Run as administrator。


    下面看看这几个函数的实现:

    Service.h

    #pragma once
    
    // Internal name of the service
    #define SERVICE_NAME             L"CppWin8Service"
    
    // Displayed name of the service
    #define SERVICE_DISPLAY_NAME     L"CppWin8Service Demo"
    
    // List of service dependencies - "dep1\0dep2\0\0"
    #define SERVICE_DEPENDENCIES     L""
    
    // The name of the account under which the service should run
    #define SERVICE_ACCOUNT          L"NT AUTHORITY\\LocalService"
    
    // The password to the service account name
    #define SERVICE_PASSWORD         NULL
    
    VOID RunService();
    VOID SvcInstall();
    VOID SvcUninstall();
    VOID SvcQueryConfig();
    BOOL SvcStart();
    VOID SvcStopNow();


    Service.cpp

    #pragma region "Includes"
    #include <stdio.h>
    #include <windows.h>
    #include "Service.h"
    #pragma endregion
    
    
    SERVICE_STATUS          g_ssSvcStatus;         // Current service status
    SERVICE_STATUS_HANDLE   g_sshSvcStatusHandle;  // Current service status handle
    HANDLE                  g_hSvcStopEvent;
    
    
    VOID WINAPI SvcMain(DWORD dwArgc, LPWSTR* lpszArgv);
    VOID WINAPI SvcCtrlHandler(DWORD dwCtrl);
    VOID SvcInit(DWORD dwArgc, LPWSTR* lpszArgv);
    VOID SvcStop();
    VOID SvcReportStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
    VOID SvcReportEvent(LPWSTR lpszFunction, DWORD dwErr = 0);
    
    
    VOID RunService()
    {
    	// You can add any additional services for the process to this table.
    	SERVICE_TABLE_ENTRY dispatchTable[] = 
    	{
    		{ SERVICE_NAME, (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))
    	{
    		SvcReportEvent(L"StartServiceCtrlDispatcher", GetLastError());
    	}
    }
    
    
    VOID WINAPI SvcMain(DWORD dwArgc, LPWSTR* lpszArgv)
    {
    	SvcReportEvent(L"Enter SvcMain");
    
    	// Register the handler function for the service
    	g_sshSvcStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, 
    		SvcCtrlHandler);
    	if (!g_sshSvcStatusHandle)
    	{
    		SvcReportEvent(L"RegisterServiceCtrlHandler", GetLastError());
    		return; 
    	} 
    
    	// These SERVICE_STATUS members remain as set here
    	g_ssSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 
    	g_ssSvcStatus.dwServiceSpecificExitCode = 0;
    
    	// Report initial status to the SCM
    	SvcReportStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
    
    	// Perform service-specific initialization and work.
    	SvcInit(dwArgc, lpszArgv);
    }
    
    
    VOID WINAPI SvcCtrlHandler(DWORD dwCtrl)
    {
    	// Handle the requested control code.
    	switch(dwCtrl) 
    	{  
    	case SERVICE_CONTROL_STOP: 
    		// Stop the service
    
    		// SERVICE_STOP_PENDING should be reported before setting the Stop 
    		// Event - g_hSvcStopEvent - in SvcStop(). This avoids a race 
    		// condition which may result in a 1053 - The Service did not 
    		// respond... error.
    		SvcReportStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
    
    		SvcStop();
    
    		SvcReportStatus(g_ssSvcStatus.dwCurrentState, NO_ERROR, 0);
    
    		return;
    
    	case SERVICE_CONTROL_INTERROGATE: 
    		break; 
    
    	default:
    		break;
    	} 
    
    }
    
    
    VOID SvcInit(DWORD dwArgc, LPWSTR* lpszArgv)
    {
    	SvcReportEvent(L"Enter SvcInit");
    
    	/////////////////////////////////////////////////////////////////////////
    	// Service initialization.
    	// 
    
    	// 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 a manual-reset event that is not signaled at first. The control 
    	// handler function, SvcCtrlHandler, signals this event when it receives 
    	// the stop control code.
    	g_hSvcStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    	if (g_hSvcStopEvent == NULL)
    	{
    		SvcReportStatus(SERVICE_STOPPED, NO_ERROR, 0);
    		return;
    	}
    
    	// Report running status when initialization is complete.
    	SvcReportStatus(SERVICE_RUNNING, NO_ERROR, 0);
    
    
    	/////////////////////////////////////////////////////////////////////////
    	// Perform work until service stops.
    	// 
    
    	while(TRUE)
    	{
    		// Perform work ...
    
    		// Check whether to stop the service.
    		WaitForSingleObject(g_hSvcStopEvent, INFINITE);
    
    		SvcReportStatus(SERVICE_STOPPED, NO_ERROR, 0);
    		return;
    	}
    }
    
    
    VOID SvcStop()
    {
    	SvcReportEvent(L"Enter SvcStop");
    
    	// Signal the service to stop.
    	if (g_hSvcStopEvent)
    	{
    		SetEvent(g_hSvcStopEvent);
    	}
    }
    
    
    VOID SvcReportStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, 
    					 DWORD dwWaitHint)
    {
    	static DWORD dwCheckPoint = 1;
    
    	// Fill in the SERVICE_STATUS structure.
    
    	g_ssSvcStatus.dwCurrentState = dwCurrentState;
    	g_ssSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
    	g_ssSvcStatus.dwWaitHint = dwWaitHint;
    
    	g_ssSvcStatus.dwControlsAccepted = 
    		(dwCurrentState == SERVICE_START_PENDING) ? 
    		0 : SERVICE_ACCEPT_STOP;
    
    	g_ssSvcStatus.dwCheckPoint = 
    		((dwCurrentState == SERVICE_RUNNING) || 
    		(dwCurrentState == SERVICE_STOPPED)) ? 
    		0 : dwCheckPoint++;
    
    	// Report the status of the service to the SCM.
    	SetServiceStatus(g_sshSvcStatusHandle, &g_ssSvcStatus);
    }
    
    
    VOID SvcReportEvent(LPWSTR lpszFunction, DWORD dwErr) 
    {
    	HANDLE hEventSource;
    	LPCWSTR lpszStrings[2];
    	wchar_t szBuffer[80];
    
    	hEventSource = RegisterEventSource(NULL, SERVICE_NAME);
    	if (NULL != hEventSource)
    	{
    		WORD wType;
    		if (dwErr == 0)
    		{
    			swprintf_s(szBuffer, ARRAYSIZE(szBuffer), lpszFunction);
    			wType = EVENTLOG_INFORMATION_TYPE;
    		}
    		else
    		{
    			swprintf_s(szBuffer, ARRAYSIZE(szBuffer), L"%s failed w/err 0x%08lx", 
    				lpszFunction, dwErr);
    			wType = EVENTLOG_ERROR_TYPE;
    		}
    
    		lpszStrings[0] = SERVICE_NAME;
    		lpszStrings[1] = szBuffer;
    
    		ReportEvent(hEventSource,  // Event log handle
    			wType,                 // Event type
    			0,                     // Event category
    			0,                     // 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);
    	}
    }
    
    VOID SvcInstall()
    {
    	wchar_t szPath[MAX_PATH];
    	if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
    	{
    		wprintf(L"GetModuleFileName failed w/err 0x%08lx\n", GetLastError());
    		return;
    	}
    
    	// Open the local default service control manager database
    	SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, 
    		SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
    	if (!schSCManager)
    	{
    		wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
    		return;
    	}
    
    	// Install the service into SCM by calling CreateService
    	SC_HANDLE schService = CreateService(
    		schSCManager,                   // SCManager database
    		SERVICE_NAME,                   // Name of service
    		SERVICE_DISPLAY_NAME,           // Name to display
    		SERVICE_CHANGE_CONFIG,          // Desired access
    		SERVICE_WIN32_OWN_PROCESS,      // Service type
    		SERVICE_DEMAND_START,           // Start type
    		SERVICE_ERROR_NORMAL,           // Error control type
    		szPath,                         // Service's binary
    		NULL,                           // No load ordering group
    		NULL,                           // No tag identifier
    		SERVICE_DEPENDENCIES,           // Dependencies
    		SERVICE_ACCOUNT,                // Service running account
    		SERVICE_PASSWORD);              // Password of the account
    
    	if (NULL != schService)
    	{
    		wprintf(L"%s installed.\n", SERVICE_DISPLAY_NAME);
    
    		CloseServiceHandle(schService);
    	}
    	else
    	{
    		wprintf(L"CreateService failed w/err 0x%08lx\n", GetLastError());
    	}
    
    	CloseServiceHandle(schSCManager);
    }
    
    VOID SvcUninstall()
    {
    	// Open the local default service control manager database
    	SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    	if (!schSCManager)
    	{
    		wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
    		return;
    	}
    
    	// Open the service with delete, stop and query status permissions
    	SC_HANDLE schService = OpenService(schSCManager, SERVICE_NAME, 
    		DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
    
    	if (NULL != schService)
    	{
    		// Try to stop the service
    		SERVICE_STATUS ssSvcStatus;
    		if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus))
    		{
    			wprintf(L"Stopping %s.", SERVICE_DISPLAY_NAME);
    			Sleep(1000);
    
    			while (QueryServiceStatus(schService, &ssSvcStatus))
    			{
    				if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING)
    				{
    					wprintf(L".");
    					Sleep(1000);
    				}
    				else break;
    			}
    
    			if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED)
    			{
    				wprintf(L"\n%s stopped.\n", SERVICE_DISPLAY_NAME);
    			}
    			else
    			{
    				wprintf(L"\n%s failed to stop.\n", SERVICE_DISPLAY_NAME);
    			}
    		}
    
    		// Now remove the service by calling DeleteService
    		if (DeleteService(schService))
    		{
    			wprintf(L"%s removed.\n", SERVICE_DISPLAY_NAME);
    		}
    		else
    		{
    			wprintf(L"DeleteService failed w/err 0x%08lx\n", GetLastError());
    		}
    
    		CloseServiceHandle(schService);
    	}
    	else
    	{
    		wprintf(L"OpenService failed w/err 0x%08lx\n", GetLastError());
    	}
    
    	CloseServiceHandle(schSCManager);
    }
    
    VOID SvcQueryConfig()
    {
    	// Open the local default service control manager database
    	SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    	if (!schSCManager)
    	{
    		wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
    		return;
    	}
    
    	// Try to open the service to query its status and config
    	SC_HANDLE schService = OpenService(schSCManager, SERVICE_NAME, 
    		SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
    
    	if (NULL != schService)
    	{
    		wprintf(L"%s was installed.\n", SERVICE_DISPLAY_NAME);
    
    		DWORD cbBytesNeeded;
    
    		// 
    		// Query the status of the service
    		// 
    
    		SERVICE_STATUS_PROCESS ssp;
    		if (QueryServiceStatusEx(schService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, 
    			sizeof(ssp), &cbBytesNeeded))
    		{
    			wprintf(L"Service status: ");
    			switch (ssp.dwCurrentState)
    			{
    			case SERVICE_STOPPED: _putws(L"Stopped"); break;
    			case SERVICE_RUNNING: _putws(L"Running"); break;
    			case SERVICE_PAUSED: _putws(L"Paused"); break;
    			case SERVICE_START_PENDING:
    			case SERVICE_STOP_PENDING:
    			case SERVICE_CONTINUE_PENDING:
    			case SERVICE_PAUSE_PENDING: _putws(L"Pending"); break;
    			}
    		}
    		else
    		{
    			wprintf(L"QueryServiceStatusEx failed w/err 0x%08lx\n", GetLastError());
    		}
    		
    		CloseServiceHandle(schService);
    	}
    	else
    	{
    		DWORD dwErr = GetLastError();
    		if (dwErr == ERROR_SERVICE_DOES_NOT_EXIST)
    		{
    			wprintf(L"%s was not installed.\n", SERVICE_DISPLAY_NAME);
    		}
    		else
    		{
    			wprintf(L"OpenService failed w/err 0x%08lx\n", dwErr);
    		}
    	}
    
    	CloseServiceHandle(schSCManager);
    }
    
    BOOL SvcStart() 
    { 
    	// run service with given name
    	SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); 
    	if (schSCManager==0) 
    	{
    		long nError = GetLastError();
    		wprintf(L"OpenSCManager failed, error code = %d\n", nError);
    	}
    	else
    	{
    		// open the service
    		SC_HANDLE schService = OpenService( schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
    		if (schService==0) 
    		{
    			long nError = GetLastError();
    			wprintf(L"OpenService failed, error code = %d\n", nError);
    		}
    		else
    		{
    			// call StartService to run the service
    			if(StartService(schService, 0, (LPCWSTR*)NULL))
    			{
                    wprintf(L"%s started.\n", SERVICE_DISPLAY_NAME);
    				CloseServiceHandle(schService); 
    				CloseServiceHandle(schSCManager); 
    				return TRUE;
    			}
    			else
    			{
    				long nError = GetLastError();
    				wprintf(L"StartService failed, error code = %d\n", nError);
    			}
    			CloseServiceHandle(schService); 
    		}
    		CloseServiceHandle(schSCManager); 
    	}
    	return FALSE;
    }
    
    VOID SvcStopNow() 
    {
    	// Open the local default service control manager database
    	SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    	if (!schSCManager)
    	{
    		wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
    		return;
    	}
    
    	// Open the service with delete, stop and query status permissions
    	SC_HANDLE schService = OpenService(schSCManager, SERVICE_NAME, 
    		DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
    
    	if (NULL != schService)
    	{
    		// Try to stop the service
    		SERVICE_STATUS ssSvcStatus;
    		if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus))
    		{
    			wprintf(L"Stopping %s.", SERVICE_DISPLAY_NAME);
    			Sleep(1000);
    
    			while (QueryServiceStatus(schService, &ssSvcStatus))
    			{
    				if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING)
    				{
    					wprintf(L".");
    					Sleep(1000);
    				}
    				else break;
    			}
    
    			if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED)
    			{
    				wprintf(L"\n%s stopped.\n", SERVICE_DISPLAY_NAME);
    			}
    			else
    			{
    				wprintf(L"\n%s failed to stop.\n", SERVICE_DISPLAY_NAME);
    			}
    		}
    
    		CloseServiceHandle(schService);
    	}
    	else
    	{
    		wprintf(L"OpenService failed w/err 0x%08lx\n", GetLastError());
    	}
    
    	CloseServiceHandle(schSCManager);
    }

    下面看看运行结果如何。

    WIN+R,调出RUN,输入services.msc调出Service管理。在这里你就会看见CppWin8Service Demo,点击一下,会发现其没有运行。

    我们在刚刚install的控制台继续运行:

    D:\honeywell\workspace\Win8Service\Debug>Win8Service.exe -install
    CppWin8Service Demo installed.
    
    D:\honeywell\workspace\Win8Service\Debug>Win8Service.exe -start
    CppWin8Service Demo started.

    刷新一下Service,会看到此服务以及启动。

    打开事件查看器(运行eventvwr.msc),Windows logs---》Application中可以看到CppWin8Service的infomation,比如:

    CppWin8Service
    Enter SvcInit
    

    二、外部程序启动和停止此服务

    服务跑起来了,那么我们如何在外部程序中控制它呢?其实很简单,就是用上面的SvcStart和SvcStopNow方法来做就可以了。

    我们新建一个MFC对话框程序,加两个button,一个启动一个停止。将两个函数拷进去,然后包含一下此头文件就可以了。

    #include <winsvc.h> 


    三、批处理安装服务程序

    说白了,就是用sc命令来安装启动服务程序,用批处理来包装一下,注意运行批处理时也要用admin。

    sc命令见sc命令创建启动服务。

    Service安装和启动的bat:

    @echo. start service!
    @echo off
    
    @sc create LincTestServer binPath= "D:\XXX\Debug\NewService.exe"
    
    @sc start LincTestServer 
    
    @sc config LincTestServer start= AUTO
    
    @sc config LincTestServer displayname="linc service"
    @echo off
    
    @echo. start ok!
    @pause
    
    
    


    停止的bat:

    @echo.stop service
    @echo off
    
    @sc stop LincTestServer 
    @echo off
    
    @echo.service stoped
    
    @pause


    卸载的bat:

    @echo.delete service
    @echo off
    
    @sc delete LincTestServer 
    @echo off
    
    @echo.service deleted
    
    @pause






    
    


沪ICP备19023445号-2号
友情链接