在windows vista&以上,
目前,我正在枚举所有的Windows会话,然后一旦找到活动会话,就会调用WTSQueryUserToken(),它会给我当前用户的标记。
此令牌用于在桌面内以他的权限启动进程。
我面临的问题是,没有可靠的方法来获取活动会话/交互式会话。我必须等待(每隔几毫秒检查一次),直到explorer.exe产生。
我不喜欢用户登录的SENS(系统通知服务)等通知。
收到SERVICE_CONTROL_SESSIONCHANGE / logon事件后,我调用WTSGetActiveConsoleSessionId()来获取当前会话,然后使用此会话ID和WTSQueryUserToken()来获取令牌。
WTSGetActiveConsoleSessionId()有时会返回会话0.因此,当我需要来自当前登录用户的会话的令牌时,我最终得到会话0的令牌。
这取决于WTSGetActiveConsoleSessionId()调用的时间。
通过实验我想出了等待explorer.exe的想法,并且只有在它出现之后调用WTSGetActiveConsoleSessionId(),这似乎保证我总是得到会话1或更高版本,从而相应的令牌。
寻求更清洁的方法。
答案 0 :(得分:2)
收到SERVICE_CONTROL_SESSIONCHANGE / logon事件后,我调用WTSGetActiveConsoleSessionId()来获取当前会话,然后使用此会话ID和WTSQueryUserToken()来获取令牌。
您应该使用SERVICE_CONTROL_SESSIONCHANGE
本身报告的会话ID。 lpEventData
参数将是指向WTSSESSION_NOTIFICATION
结构的指针,其中包含dwSessionId
字段。
WTSGetActiveConsoleSessionId()有时会返回会话0。
WTSGetActiveConsoleSessionId()
返回连接到本地计算机的物理控制台(鼠标/键盘/监视器)的会话。它永远不会在Vista及更高版本中报告会话0(由于会话0隔离),但它可以在XP中(登录的第一个交互式用户使用会话0)。但是,即使它可以报告会话0,也不能保证与登录用户关联的正确会话。还有其他方式登录到计算机而不是通过其物理控制台。例如,远程桌面。
因此,当我需要来自当前登录用户的会话的令牌时,我最终得到会话0的令牌。
您需要查询用户实际登录的会话。 SERVICE_CONTROL_SESSIONCHANGE
告诉您实际的会话ID,在Vista及更高版本中永远不会为0(由于会话0隔离)。
通过实验我想出了等待explorer.exe的想法,并且只有在它出现之后调用WTSGetActiveConsoleSessionId(),这似乎保证我总是得到会话1或更高版本,从而相应的令牌。
但这不能保证该活动控制台会话是要查询的正确会话。
寻求更清洁的方法。
使用通知明确告诉您的会话ID。不要去追捕它。
答案 1 :(得分:0)
我知道这是一个老问题,但仅供将来参考,以澄清人头马的答案...
如果我们假设您的服务控制处理程序称为ServiceControlHandler,那么您要执行以下操作:
DWORD ServiceControlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
DWORD retval = ERROR_CALL_NOT_IMPLEMENTED;
switch (dwControl)
{
case SERVICE_CONTROL_INTERROGATE: // All services should handle this message
retval = NO_ERROR;
break;
case SERVICE_CONTROL_SESSIONCHANGE: // Assumes you registered for these when you created the service
{
auto data = reinterpret_cast<WTSSESSION_NOTIFICATION*>(lpEventData);
if (data)
{
DWORD sessionId = data->dwSessionId; // Now you have the actual session ID
retval = NO_ERROR; // indicates we handled the message.
switch (dwEventType)
{
case WTS_CONSOLE_CONNECT:
// TODO: Do what you wish
break;
case WTS_CONSOLE_DISCONNECT:
// TODO: Do what you wish
break;
case WTS_REMOTE_CONNECT:
// TODO: Do what you wish
break;
case WTS_REMOTE_DISCONNECT:
// TODO: Do what you wish
break;
case WTS_SESSION_LOGON:
// TODO: Do what you wish
break;
case WTS_SESSION_LOGOFF:
// TODO: Do what you wish
break;
case WTS_SESSION_LOCK:
// TODO: Do what you wish
break;
case WTS_SESSION_UNLOCK:
// TODO: Do what you wish
break;
case WTS_SESSION_REMOTE_CONTROL:
// TODO: Do what you wish
break;
case WTS_SESSION_CREATE: // (0xA) Reserved for future use.
case WTS_SESSION_TERMINATE: // (0xB) Reserved for future use.
default:
break; // do nothing
}
}
else
{
// NOTE: should never happen
}
}
break;
// TODO: Handle other control types here
default:
retval = ERROR_CALL_NOT_IMPLEMENTED; // must always return this if not handled
break;
};
return retval;
}
正如雷米(Remy)所说,通过这种方式,您可以使用通知明确告知您的会话ID,而不是去寻找错误的会话ID。