调用WinAPI StartService启动w32Time服务时出现1058错误的问题咨询
问题描述
我运行微软官方的启动服务示例代码,使用Windows 10 21H2系统,操作步骤如下:
- 关闭「控制面板」>「日期和时间」>「与Internet时间同步」并确定;

- 执行自定义代码(完整代码见下方),触发1058错误,提示:服务无法启动,原因是已禁用或没有关联的启用设备;

重新开启「与Internet时间同步」后,代码可正常运行。我排查多日未找到原因,猜测当服务处于停止状态时StartService API无法正常工作,请问该猜测是否正确?
补充:我发现当services.msc中w32Time服务的启动类型为「禁用」时,StartService会抛出1058错误,额外想了解用户程序是否无法自动或手动修改已禁用的服务?
解答
关于StartService API的猜测
你的猜测不正确。StartService API可以正常启动处于停止状态的服务,1058错误的核心原因并非服务处于停止状态,而是服务的启动类型被设置为「禁用」。
当你关闭「与Internet时间同步」时,系统会自动将w32Time服务的启动类型从「手动」或「自动」改为「禁用」,此时调用StartService就会触发1058错误;重新开启同步后,系统又会将服务启动类型改回可启动状态,因此代码能正常运行。
关于修改已禁用服务的权限
用户程序可以修改已禁用服务的启动类型,但需要满足两个条件:
- 程序必须以管理员权限运行;
- 调用
ChangeServiceConfigAPI,将服务的启动类型修改为SERVICE_DEMAND_START(手动)或SERVICE_AUTO_START(自动)等可启动类型,之后才能调用StartService启动服务。
需要注意的是,修改系统服务的启动类型可能影响系统功能,操作前需确认必要性。
完整测试代码
// servicetest.cpp : 이 파일에는 'main' 함수가 포함됩니다. 거기서 프로그램 실행이 시작되고 종료됩니다. // #include <iostream> #include <Windows.h> VOID __stdcall DoStartSvc(LPCWSTR szSvcName); int main() { std::cout << "Hello World!\n"; const WCHAR *name = L"w32Time"; DoStartSvc(name); } VOID __stdcall DoStartSvc(LPCWSTR szSvcName) { SERVICE_STATUS_PROCESS ssStatus; DWORD dwOldCheckPoint; DWORD dwStartTickCount; DWORD dwWaitTime; DWORD dwBytesNeeded; // Get a handle to the SCM database. SC_HANDLE 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; } // Get a handle to the service. SC_HANDLE schService = OpenService( schSCManager, // SCM database szSvcName, // name of service SERVICE_ALL_ACCESS); // full access if (schService == NULL) { printf("OpenService failed (%d)\n", GetLastError()); CloseServiceHandle(schSCManager); return; } // Check the status in case the service is not stopped. if (!QueryServiceStatusEx( schService, // handle to service SC_STATUS_PROCESS_INFO, // information level (LPBYTE)&ssStatus, // address of structure sizeof(SERVICE_STATUS_PROCESS), // size of structure &dwBytesNeeded)) // size needed if buffer is too small { printf("QueryServiceStatusEx failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return; } // Check if the service is already running. It would be possible // to stop the service here, but for simplicity this example just returns. if (ssStatus.dwCurrentState != SERVICE_STOPPED && ssStatus.dwCurrentState != SERVICE_STOP_PENDING) { printf("Cannot start the service because it is already running\n"); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return; } // Save the tick count and initial checkpoint. dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; // Wait for the service to stop before attempting to start it. while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING) { // Do not wait longer than the wait hint. A good interval is // one-tenth of the wait hint but not less than 1 second // and not more than 10 seconds. dwWaitTime = ssStatus.dwWaitHint / 10; if (dwWaitTime < 1000) dwWaitTime = 1000; else if (dwWaitTime > 10000) dwWaitTime = 10000; Sleep(dwWaitTime); // Check the status until the service is no longer stop pending. if (!QueryServiceStatusEx( schService, // handle to service SC_STATUS_PROCESS_INFO, // information level (LPBYTE)&ssStatus, // address of structure sizeof(SERVICE_STATUS_PROCESS), // size of structure &dwBytesNeeded)) // size needed if buffer is too small { printf("QueryServiceStatusEx failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return; } if (ssStatus.dwCheckPoint > dwOldCheckPoint) { // Continue to wait and check. dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint) { printf("Timeout waiting for service to stop\n"); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return; } } } // Attempt to start the service. if (!StartService( schService, // handle to service 0, // number of arguments NULL)) // no arguments { printf("StartService failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return; } else printf("Service start pending...\n"); // Check the status until the service is no longer start pending. 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 { printf("QueryServiceStatusEx failed (%d)\n", GetLastError()); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return; } // Save the tick count and initial checkpoint. dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; while (ssStatus.dwCurrentState == SERVICE_START_PENDING) { // Do not wait longer than the wait hint. A good interval is // one-tenth the wait hint, but no less than 1 second and no // more than 10 seconds. dwWaitTime = ssStatus.dwWaitHint / 10; if (dwWaitTime < 1000) dwWaitTime = 1000; else if (dwWaitTime > 10000) dwWaitTime = 10000; Sleep(dwWaitTime); // Check the status again. 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 { printf("QueryServiceStatusEx failed (%d)\n", GetLastError()); break; } if (ssStatus.dwCheckPoint > dwOldCheckPoint) { // Continue to wait and check. dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint) { // No progress made within the wait hint. break; } } } // Determine whether the service is running. if (ssStatus.dwCurrentState == SERVICE_RUNNING) { printf("Service started successfully.\n"); } else { printf("Service not started. \n"); printf(" Current State: %d\n", ssStatus.dwCurrentState); printf(" Exit Code: %d\n", ssStatus.dwWin32ExitCode); printf(" Check Point: %d\n", ssStatus.dwCheckPoint); printf(" Wait Hint: %d\n", ssStatus.dwWaitHint); } CloseServiceHandle(schService); CloseServiceHandle(schSCManager); }
内容的提问来源于stack exchange,提问作者june
相关产品推荐
相关产品推荐

