如何使用C+;从windows服务中获取登录用户的令牌+;?
在windows vista及以上版本上 当前,我正在枚举所有windows会话,然后一旦找到活动会话,就会调用WTSQueryUserToken(),它将为我提供当前用户的令牌 此令牌用于以其权限/在其桌面内启动进程 我面临的问题是,没有可靠的方法来获取活动会话/交互式会话。我必须等待(每隔几毫秒检查一次),直到生成explorer.exe 我不喜欢用户登录的SENS(系统通知服务)的通知如何使用C+;从windows服务中获取登录用户的令牌+;?,windows,winapi,visual-c++,Windows,Winapi,Visual C++,在windows vista及以上版本上 当前,我正在枚举所有windows会话,然后一旦找到活动会话,就会调用WTSQueryUserToken(),它将为我提供当前用户的令牌 此令牌用于以其权限/在其桌面内启动进程 我面临的问题是,没有可靠的方法来获取活动会话/交互式会话。我必须等待(每隔几毫秒检查一次),直到生成explorer.exe 我不喜欢用户登录的SENS(系统通知服务)的通知 编辑 在接收服务\u控制\u会话更改/登录事件时,我调用WTSGetActiveConsoleSess
编辑 在接收服务\u控制\u会话更改/登录事件时,我调用WTSGetActiveConsoleSessionId()获取当前会话,然后使用此会话ID和WTSQueryUserToken()获取令牌 WTSGetActiveConsoleSessionId()有时会返回会话0。因此,当我想要从当前登录用户的会话中获得令牌时,我最终得到会话0的令牌 这取决于WTSGetActiveConsoleSessionId()调用的时间 通过实验,我想出了等待explorer.exe的想法,并且只有在它调用WTSGetActiveConsoleSessionId()之后,这似乎保证了我总是获得会话1或更高版本,以及相应的令牌 寻求更干净的方法 在接收服务\u控制\u会话更改/登录事件时,我调用WTSGetActiveConsoleSessionId()获取当前会话,然后使用此会话ID和WTSQueryUserToken()获取令牌 您应该使用由
服务\u控制\u会话更改
本身报告的会话ID。lpEventData
参数将是指向结构的指针,该结构包含dwSessionId
字段
WTSGetActiveConsoleSessionId()有时会返回会话0
WTSGetActiveConsoleSessionId()
返回连接到本地计算机的物理控制台(鼠标/键盘/监视器)的会话。它永远不能在Vista和更高版本中报告会话0(由于会话0隔离),但在XP中可以报告会话0(第一个登录的交互用户使用会话0)。但是,即使它可以报告会话0,也不能保证该会话是与登录用户关联的正确会话。除了通过物理控制台登录计算机之外,还有其他方法。例如,远程桌面
因此,当我想要从当前登录用户的会话中获得令牌时,我最终得到会话0的令牌
您需要查询用户实际登录的会话SERVICE\u CONTROL\u SESSIONCHANGE
告诉您实际的会话ID,它在Vista和更高版本上永远不会为0(由于会话0隔离)
通过实验,我想出了等待explorer.exe的想法,并且只有在它调用WTSGetActiveConsoleSessionId()之后,这似乎保证了我总是获得会话1或更高版本,以及相应的令牌
但这并不能保证活动控制台会话是要查询的正确会话
寻求更干净的方法
使用通知明确告诉您的会话ID。不要找它
在接收服务\u控制\u会话更改/登录事件时,我调用WTSGetActiveConsoleSessionId()获取当前会话,然后使用此会话ID和WTSQueryUserToken()获取令牌
您应该使用由服务\u控制\u会话更改
本身报告的会话ID。lpEventData
参数将是指向结构的指针,该结构包含dwSessionId
字段
WTSGetActiveConsoleSessionId()有时会返回会话0
WTSGetActiveConsoleSessionId()
返回连接到本地计算机的物理控制台(鼠标/键盘/监视器)的会话。它永远不能在Vista和更高版本中报告会话0(由于会话0隔离),但在XP中可以报告会话0(第一个登录的交互用户使用会话0)。但是,即使它可以报告会话0,也不能保证该会话是与登录用户关联的正确会话。除了通过物理控制台登录计算机之外,还有其他方法。例如,远程桌面
因此,当我想要从当前登录用户的会话中获得令牌时,我最终得到会话0的令牌
您需要查询用户实际登录的会话SERVICE\u CONTROL\u SESSIONCHANGE
告诉您实际的会话ID,它在Vista和更高版本上永远不会为0(由于会话0隔离)
通过实验,我想出了等待explorer.exe的想法,并且只有在它调用WTSGetActiveConsoleSessionId()之后,这似乎保证了我总是获得会话1或更高版本,以及相应的令牌
但这并不能保证活动控制台会话是要查询的正确会话
寻求更干净的方法
使用通知明确告诉您的会话ID。不要找它
在接收服务\u控制\u会话更改/登录事件时,我调用WTSGetActiveConsoleSessionId()获取当前会话,然后使用此会话ID和WTSQueryUserToken()获取令牌
您应该使用由服务\u控制\u会话更改
本身报告的会话ID。lpEventData
参数将是指向结构的指针,该结构包含dwSessionId
字段
WTSGetActiveConsoleSessionId()有时会返回会话0
WTSGetActiveConsoleSessionId()
返回连接到本地计算机的物理控制台(鼠标/键盘/监视器)的会话。它永远不能在Vista和更高版本中报告会话0(由于会话0隔离),但在XP中可以报告会话0(第一个登录的交互用户使用会话0)。但是,即使它可以报告会话0,也不能保证是正确的
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;
}