借助MSDN上Win7 Service的Demo和《用VC++建立Service服务应用程序》,在Win8上经历各种磨难,终于跑起来自己改装的服务程序了。http://blog.youkuaiyun.com/lincyang/article/details/25305311
原来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