【问题标题】:WTSIsRemoteSession always returns TRUEWTSIsRemoteSession 始终返回 TRUE
【发布时间】:2023-03-27 03:00:01
【问题描述】:

我目前正在编写一个 Windows 服务,当用户登录时它也会做一些事情。如果登录来自远程计算机(例如远程桌面),则有什么都不做的想法,并试图找到一种方法来解决这个问题。但以下不起作用 - 它总是返回 true(Windows 10 64 位 V1809) - 我在这里做错了吗?

DWORD SvcHandlerEx(DWORD controlCode, DWORD eventType, ... )
{
    ...

    switch(controlCode)
    {
        case SERVICE_CONTROL_SESSIONCHANGE:
        {
            WTSSESSION_NOTIFICATION *pSessInfo = (WTSSESSION_NOTIFICATION *)pEvtData;
            // invoke SessionChangeHandler(eventId, pSessInfo->dwSessionId)
        }

        ...
    }

    ...
}

...

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    LPWSTR *pSessionInfo = nullptr;
    DWORD dataLen = 0;
    BOOL isRDP = false;

    if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, 
                                     WTSIsRemoteSession, &pSessionInfo, &dataLen))
    {
        // Do some error handling...
        return;
    }

    if (dataLen)
    {
        if (dataLen)
        {
            isRDP = (bool)pSessionInfo;    // Always 1 (TRUE) !!!
        }

        WTSFreeMemory(pSessionInfo);
    }

    ...

}

【问题讨论】:

  • 我也尝试使用 WTSClientProtocolType,如 stackoverflow.com/questions/33001915/… 中所述 - 但在这种情况下,从远程计算机连接时我没有得到“2”(RDP 协议)......奇怪。

标签: windows winapi service


【解决方案1】:

根据documentationWTSIsRemoteSession

WTSIsRemoteSession

确定当前会话是否为远程会话。

WTSQuerySessionInformation 函数返回值TRUE 表示当前会话是远程会话,FALSE 表示当前会话是本地会话。该值只能用于本地机器,所以WTSQuerySessionInformation函数的hServer参数必须包含WTS_CURRENT_SERVER_HANDLE

Windows Server 2008 和 Windows Vista:不支持此值。

这意味着WTSQuerySessionInformation()返回值 包含您要查找的值,并且函数可能分配的任何内存(如果有)都是次要的,在查询WTSIsRemoteSession 时应忽略,例如:

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    LPWSTR *pSessionInfo = nullptr;
    DWORD dataLen = 0;

    bool isRDP = WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, &pSessionInfo, &dataLen);
    if ((!isRDP) && (GetLastError() != 0))
    {
        // Do some error handling...
        return;
    }

    if (pSessionInfo)
        WTSFreeMemory(pSessionInfo);

    // use isRDP as needed...
    ...
}

但是,如果您发现isRDP 在这种情况下始终为真,那么文档具有误导性,您应该检查pSessionInfo 缓冲区的内容。您正在根据 WTSQuerySessionInformation() 是否分配任何内存来设置您的 isRDP 变量,您并没有查看数据中的实际内容。

例如,假设 dataLen 在输出时被设置为 sizeof(BOOL) 然后将您的 pSessionInfo 指针转换为 BOOL* 指针并取消引用它,例如:

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    LPWSTR *pSessionInfo = nullptr;
    DWORD dataLen = 0;

    if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, &pSessionInfo, &dataLen))
    {
        // Do some error handling...
        return;
    }

    bool isRDP = * (BOOL*) pSessionInfo;
    WTSFreeMemory(pSessionInfo);

    // use isRDP as needed...
    ...
}

或者:

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    BOOL *isRDP = nullptr;
    DWORD dataLen = 0;

    if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, (LPWSTR*)&isRDP, &dataLen))
    {
        // Do some error handling...
        return;
    }

    // use isRDP as needed...

    WTSFreeMemory(isRDP);
    ...
}

【讨论】:

  • 看来我误解了文档(或者措辞不好 - “WTSQuerySessionInformationW 的返回值返回......”可能更清楚)。但是,我按照您的建议进行了尝试:GetLastError() 返回 0(在 WTSQuerySessionInformationW 之后立即调用),但“isRdp”始终为“TRUE”。可以肯定的是,我在没有通过远程桌面连接的情况下重新启动并检查了这个 - “isRdp”是“TRUE”。我还尝试通过“if (GetLastError() != 0)”捕获错误——没有任何变化。是否有其他方法可以确定远程桌面连接是否已建立?
  • 非常感谢 - 你帮了我很多。我明白了:我对 WTSQuerySessionInformationW() 的使用是正确的,但我没有正确取消引用数据(我做了“isRdp = (bool)pSessionInfo”而不是“isRdp =*(bool *)pSessionInfo”)。一个小错误 - 大影响....
  • @WillyK。请注意,Microsoft 在其 API 中不使用 bool(小写字母),它(通常)使用 BOOL(大写字母)代替,以便与 C 兼容。请参阅BOOL vs. VARIANT_BOOL vs. BOOLEAN vs. bool:“最新消息是 @987654345 @,它是一种 C++ 数据类型,其值为 truefalse您不会在 Win32 中看到它被大量使用(如果有的话),因为 Win32 试图保持 C 兼容."
猜你喜欢
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-07
相关资源
最近更新 更多