无法关闭从服务中的用户会话的过程
问题描述:
体系结构是一个服务可以与系统特权,代码段1无法关闭从服务中的用户会话的过程
用户会话的处理组内启动一个进程当服务需要停止本身,我想发送一个信号给子进程,使它有机会优雅地关闭代码片段2.
问题是它似乎没有发送信号,没有任何明显的错误代码。我测试了从命令提示符运行的子进程,ctrl + break工作得很好。
代码片段
PROCESS_INFORMATION processInfo;
ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\Default";
si.dwFlags |= STARTF_USESTDHANDLES;
LPVOID environment;
BOOL createRet = CreateEnvironmentBlock(&environment, userToken, FALSE);
if (!createRet) {
throw std::runtime_error("Failed to create environment block");
}
DWORD creationFlags =
NORMAL_PRIORITY_CLASS |
CREATE_NO_WINDOW |
CREATE_UNICODE_ENVIRONMENT |
CREATE_NEW_PROCESS_GROUP; // this create a process in a group
// launch a process in the user session
// the toke is a system privilege toke within the user session
createRet = CreateProcessAsUser(
userToken, NULL, LPSTR(command.c_str()),
sa, NULL, TRUE, creationFlags,
environment, NULL, &si, &processInfo);
if (!createRet) {
throw std::runtime_error("Failed to create the service in user session");
}
m_serviceGroupId = processInfo.dwProcessId;
DestroyEnvironmentBlock(environment);
CloseHandle(userToken);
代码片段2
if (m_serviceGroupId == 0) {
return;
}
HANDLE process;
const UINT kExitCode = 0;
const UINT kShutdownTimeout = 3000;
if (findProcessInSession(kServiceProcess, &process, getActiveSession())) {
BOOL r = GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, m_serviceGroupId);
// this won't success if I don't specifically call AllocConsole() in the constructor
if (!r) {
writeEventErrorLog(GetLastErrorAsString().c_str());
}
DWORD exitCode = WaitForSingleObject(process, kShutdownTimeout);
if (exitCode != WAIT_OBJECT_0) {
// always fall into forceful shutdown
writeEventErrorLog("Forcefully shutdown synergy service");
// GetLastErrorAsString returns empty string
writeEventErrorLog(GetLastErrorAsString().c_str());
if (!TerminateProcess(process, kExitCode)) {
writeEventErrorLog("Failed to shutdown synergy service");
}
}
}
m_serviceGroupId = 0;
答
你的方法是行不通的,因为服务进程和子进程不在同一个会话,因此考虑使用Windows事件。看看CreateEvent和SetEvent。
当你的服务过程开始时,调用CreateEvent(),例如:
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\myevent");
当你的子进程启动,调用CreateEvent(),并启动一个线程来捕获信号:
//The lpName should be identical with that in service process
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\myevent");
std::thread mythread([hEvent] {
WaitForSingleObject(hEvent, INFINITE);
//then exit your child process gracefully
});
每当你打算停止子进程,只需调用SetEvent的()在您的服务流程:
SetEvent(hEvent);
将bManualReset设置为TRUE,然后您的服务可以同时向不同的子进程发送信号。
'GenerateConsoleCtrlEvent'远程调用'csrss'。但您的服务附加到另一个“csrss”进程 - 每个会话都有自己的“csrss”。所以'GenerateConsoleCtrlEvent'不能用于另一个会话中的发送控制事件 – RbMm
@RbMm谢谢。我有办法管理子进程吗? RPC调用? – Jerry
您需要做的只是从服务向孩子发送一次性消息,因此命名事件对象可能是最合适的选择。在更复杂的情况下,您可以使用命名管道。还有其他的选择。 –