无法查询,运行 或停止 Windows 服务
Can't query, run or stop a Windows Service
我按照 this 说明创建了我的第一个 Windows 服务。我可以从“管理”->“我的电脑”中的“服务”面板毫无问题地启动或停止我的服务。
服务帐户是 "LocalSystem" 所以,我认为我可以使用特权。
现在我想从另一个应用程序与我的服务通信,但首先我想停止或启动我的服务。
按照这个example我写这个代码:
SC_HANDLE schSCManager;
SC_HANDLE schService;
LPCWSTR szSvcName = _T("MyNewService");
// 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;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_CHANGE_CONFIG); // need change config access
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
//OK until now
// Check the status in case the service is not stopped.
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded;
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());
CString str;
str.Format(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError()); //ERROR 5: ERROR_ACCESS_DENIED
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;
}
无论如何我得到 错误编号 5,即“ERROR_ACCESS_DENIED:句柄没有 SERVICE_QUERY_STATUS访问权限”,但我不确定问题出在哪里。该服务有 LocalSystem 帐户选项,这意味着所有权限,我是我计算机的管理员。怎么了?
我也尝试使用 ControlService 尝试启动或停止服务,但我在权限方面遇到了同样的错误
BOOL success = ::ControlService(schService, SERVICE_CONTROL_STOP, &ss);
我正在 Visual Studio 2013 更新 2。
谢谢
问题
您的示例程序没有 stop/start 您的服务的正确权限。您的服务有什么特权并不重要。
解决方案
通过右键单击 exe 文件并选择 "Run as administrator",以管理员身份尝试 运行 您的示例程序。
如果您需要以编程方式提升流程,请查看 this article。
您似乎对术语 "privileges" 和 "access rights" 有点困惑。您说得对,LocalSystem 帐户确实是一个特权帐户,至少对于在本地计算机上执行的操作而言是这样。然而,即使是特权用户也必须知道如何利用她的特权(事情是如何运作的)。
当一个应用程序想要使用一个对象(例如服务)时,它必须向 Windows 内核声明它的意图(通过 OpenSCManager
和 OpenService
在你的代码)。应用程序识别对象(例如通过服务名称)并通知内核它计划用它做什么。这些 "sorts of things" 被称为 "access rights" 并且 kenrel 决定应用程序是否有足够的特权来获得它请求的访问权限。在您的代码中,您请求 SC 管理器的所有访问权限 (SC_MANAGER_ALL_ACCESS
) 和更改服务配置的访问权限 (SERVICE_CHANGE_CONFIG
)。然后,您尝试查询服务的状态,但在请求访问服务(OpenService
调用)时没有向内核声明此意图。这就是您收到 "access denied" 错误的原因。
这是为服务和 SC 管理员定义的访问权限列表:https://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx。该文档还包含有关执行哪些操作需要哪些访问权限的信息。
要打开服务,您只需要对其 SC 管理器的 SC_MANAGER_CONNECT
访问权限。要查询服务状态,需要 SERVICE-QUERY_STATUS
访问权限。要停止服务,请求 SERVICE_STOP
权限。
所以,简短的版本是:在调用 OpenService
时指定 SERVICE_STOP | SERVICE_QUERY_STATUS
所需的访问掩码,并在 OpenSCManager
调用中指定 SC_MANAGER_CONNECT
。
UINT GetServiceStatus(LPCTSTR ServiceName)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
DWORD ErrorCode;
SERVICE_STATUS ssStatus;
UINT return_value;
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if (!schSCManager)
return -1;
schService = OpenService(schSCManager, ServiceName, SERVICE_ALL_ACCESS);
if (!schService)
{
ErrorCode = GetLastError();
CloseServiceHandle(schSCManager);
if (ErrorCode == ERROR_SERVICE_DOES_NOT_EXIST)
return -2;
else
return -1;
}
QueryServiceStatus(schService, &ssStatus);
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
return_value = 1;
else
return_value = 0;
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return return_value;
}
我按照 this 说明创建了我的第一个 Windows 服务。我可以从“管理”->“我的电脑”中的“服务”面板毫无问题地启动或停止我的服务。 服务帐户是 "LocalSystem" 所以,我认为我可以使用特权。 现在我想从另一个应用程序与我的服务通信,但首先我想停止或启动我的服务。
按照这个example我写这个代码:
SC_HANDLE schSCManager;
SC_HANDLE schService;
LPCWSTR szSvcName = _T("MyNewService");
// 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;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_CHANGE_CONFIG); // need change config access
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
//OK until now
// Check the status in case the service is not stopped.
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded;
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());
CString str;
str.Format(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError()); //ERROR 5: ERROR_ACCESS_DENIED
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;
}
无论如何我得到 错误编号 5,即“ERROR_ACCESS_DENIED:句柄没有 SERVICE_QUERY_STATUS访问权限”,但我不确定问题出在哪里。该服务有 LocalSystem 帐户选项,这意味着所有权限,我是我计算机的管理员。怎么了?
我也尝试使用 ControlService 尝试启动或停止服务,但我在权限方面遇到了同样的错误
BOOL success = ::ControlService(schService, SERVICE_CONTROL_STOP, &ss);
我正在 Visual Studio 2013 更新 2。 谢谢
问题
您的示例程序没有 stop/start 您的服务的正确权限。您的服务有什么特权并不重要。
解决方案
通过右键单击 exe 文件并选择 "Run as administrator",以管理员身份尝试 运行 您的示例程序。
如果您需要以编程方式提升流程,请查看 this article。
您似乎对术语 "privileges" 和 "access rights" 有点困惑。您说得对,LocalSystem 帐户确实是一个特权帐户,至少对于在本地计算机上执行的操作而言是这样。然而,即使是特权用户也必须知道如何利用她的特权(事情是如何运作的)。
当一个应用程序想要使用一个对象(例如服务)时,它必须向 Windows 内核声明它的意图(通过 OpenSCManager
和 OpenService
在你的代码)。应用程序识别对象(例如通过服务名称)并通知内核它计划用它做什么。这些 "sorts of things" 被称为 "access rights" 并且 kenrel 决定应用程序是否有足够的特权来获得它请求的访问权限。在您的代码中,您请求 SC 管理器的所有访问权限 (SC_MANAGER_ALL_ACCESS
) 和更改服务配置的访问权限 (SERVICE_CHANGE_CONFIG
)。然后,您尝试查询服务的状态,但在请求访问服务(OpenService
调用)时没有向内核声明此意图。这就是您收到 "access denied" 错误的原因。
这是为服务和 SC 管理员定义的访问权限列表:https://msdn.microsoft.com/en-us/library/windows/desktop/ms685981(v=vs.85).aspx。该文档还包含有关执行哪些操作需要哪些访问权限的信息。
要打开服务,您只需要对其 SC 管理器的 SC_MANAGER_CONNECT
访问权限。要查询服务状态,需要 SERVICE-QUERY_STATUS
访问权限。要停止服务,请求 SERVICE_STOP
权限。
所以,简短的版本是:在调用 OpenService
时指定 SERVICE_STOP | SERVICE_QUERY_STATUS
所需的访问掩码,并在 OpenSCManager
调用中指定 SC_MANAGER_CONNECT
。
UINT GetServiceStatus(LPCTSTR ServiceName)
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
DWORD ErrorCode;
SERVICE_STATUS ssStatus;
UINT return_value;
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if (!schSCManager)
return -1;
schService = OpenService(schSCManager, ServiceName, SERVICE_ALL_ACCESS);
if (!schService)
{
ErrorCode = GetLastError();
CloseServiceHandle(schSCManager);
if (ErrorCode == ERROR_SERVICE_DOES_NOT_EXIST)
return -2;
else
return -1;
}
QueryServiceStatus(schService, &ssStatus);
if (ssStatus.dwCurrentState == SERVICE_RUNNING)
return_value = 1;
else
return_value = 0;
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return return_value;
}