如何使用C+;从windows服务中获取登录用户的令牌+;?

如何使用C+;从windows服务中获取登录用户的令牌+;?,windows,winapi,visual-c++,Windows,Winapi,Visual C++,在windows vista及以上版本上 当前,我正在枚举所有windows会话,然后一旦找到活动会话,就会调用WTSQueryUserToken(),它将为我提供当前用户的令牌 此令牌用于以其权限/在其桌面内启动进程 我面临的问题是,没有可靠的方法来获取活动会话/交互式会话。我必须等待(每隔几毫秒检查一次),直到生成explorer.exe 我不喜欢用户登录的SENS(系统通知服务)的通知 编辑 在接收服务\u控制\u会话更改/登录事件时,我调用WTSGetActiveConsoleSess

在windows vista及以上版本上

当前,我正在枚举所有windows会话,然后一旦找到活动会话,就会调用WTSQueryUserToken(),它将为我提供当前用户的令牌

此令牌用于以其权限/在其桌面内启动进程

我面临的问题是,没有可靠的方法来获取活动会话/交互式会话。我必须等待(每隔几毫秒检查一次),直到生成explorer.exe

我不喜欢用户登录的SENS(系统通知服务)的通知


编辑 在接收服务\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;
}