赞
踩
网上通用的OpenSCManager->OpenService->StartService这种启动方式是正确的,但是很多人遇到开启服务时出现1053错误,下面来分析与解决
官网对于StartServiceW的描述(我程序里用的宽字符版本)
https://docs.microsoft.com/zh-cn/windows/win32/api/winsvc/nf-winsvc-startservicew
一开始GetLastERROR错误1053,百度解决方案大致就”注册表修改超时、开启桌面交互“这两种,但是依旧不行
各种骚操作都没有解决,直到我看到官方文档对返回值的描述
ERROR_SERVICE_REQUEST_TIMEOUT | The process for the service was started, but it did not call StartServiceCtrlDispatcher, or the thread that called StartServiceCtrlDispatcher may be blocked in a control handler function. |
翻译一下:
错误\服务\请求\超时
服务的进程已启动,但它没有调用StartServiceCtrlDispatcher,或者在控制处理程序函数中可能阻止调用StartServiceCtrlDispatcher的线程。
原理这个错误的超时不仅包含启动超时,也包含线程启动后没有给管理器报告状态的超时
现在跳转到StartServiceCtrlDispatcherA的官方文档,查看它的例子
https://docs.microsoft.com/zh-cn/windows/win32/api/winsvc/nf-winsvc-startservicectrldispatchera
For an example, see Writing a Service Program's Main Function.
请结合例子描述里的另一个例子继续研究
https://docs.microsoft.com/zh-cn/windows/win32/services/svc-cpp
现在总结一下大致是这个逻辑
也就是说需要服务程序主动调用StartServiceCtrlDispatcher向管理器发送启动成功的状态,管理器才认为启动成功
所以要在运行的exe内进行”上报状态“操作才行
根据官方文档整理的服务程序代码例子,修改了注释(注册服务请自行百度解决或看官方源码),运行这个程序会在当前路径下生成SERVICE666.txt,在SvcMain函数最后都添加自己的代码,SvcInit函数是一个例子
- #include <windows.h>
- #include <tchar.h>
- #include <strsafe.h>
- //#include "sample.h"
- #pragma comment(lib, "advapi32.lib")
- #pragma warning(disable:4996)
-
- #define SVCNAME TEXT("AAA-SvcName")
-
- #define SVC_ERROR ((DWORD)0xC0020001L)
-
- SERVICE_STATUS gSvcStatus;
- SERVICE_STATUS_HANDLE gSvcStatusHandle;
- HANDLE ghSvcStopEvent = NULL;
-
- VOID WINAPI SvcCtrlHandler(DWORD);
- VOID WINAPI SvcMain(DWORD, LPTSTR *);
-
- VOID ReportSvcStatus(DWORD, DWORD, DWORD);
- VOID SvcInit(DWORD, LPTSTR *);
- VOID SvcReportEvent(LPTSTR);
-
- void __cdecl _tmain(int argc, TCHAR *argv[])
- {
- // 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))
- {
- SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
- }
- }
- //服务执行入口
- 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;
- 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);
- }
-
- //服务代码
- 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);
- //
- wchar_t szFilePath[MAX_PATH + 1] = { 0 };
- GetModuleFileNameW(NULL, szFilePath, MAX_PATH);
- (wcsrchr(szFilePath, '\\'))[1] = 0; // 删除文件名,只获得路径字串
- wcscat(szFilePath, L"SERVICE666.txt");
- FILE *file = _wfopen(szFilePath, L"wb");
- wchar_t *ptxt = L"SERVICE666:SERVICE_RUNNING";
- fwrite(ptxt, sizeof(wchar_t), wcslen(ptxt), file);
- fclose(file);
- //
- // TO_DO: Perform work until service stops.
- while (1)
- {
- // Check whether to stop the service.
- WaitForSingleObject(ghSvcStopEvent, INFINITE);
- ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
- return;
- }
- }
- //向管理器报告服务状态
- 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);
- }
-
- //每当使用controlService函数向服务发送控制代码时,由SCM调用
- 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;
- }
-
- }
- //将消息记录到事件日志
- 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);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。