C++:检查计算机是不是被锁定

Posted

技术标签:

【中文标题】C++:检查计算机是不是被锁定【英文标题】:C++: check if computer is lockedC++:检查计算机是否被锁定 【发布时间】:2015-06-02 07:35:01 【问题描述】:

我正在尝试确定计算机是否被锁定。

我查看了LockWorkStation 函数,但我希望找到的函数是IsWorkStationLocked


我需要支持所有windows版本>=XP

【问题讨论】:

您想检查计算机是否在程序运行时被锁定,或者计算机是否在程序开始执行时被锁定(如计划)?对于第一个,您可以使用 OnSessionChange 事件。 程序运行时 在 C# 上检查这个相关的question。 有人刚刚发布了执行此操作的代码:***.com/questions/29350013/… 【参考方案1】:

对于windows 7及以上可以使用WTS API:

bool IsSessionLocked() 
    typedef BOOL (PASCAL * WTSQuerySessionInformation)(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR* ppBuffer, DWORD* pBytesReturned);
    typedef void (PASCAL * WTSFreeMemory)( PVOID pMemory);

    WTSINFOEXW * pInfo = NULL;
    WTS_INFO_CLASS wtsic = DW_WTSSessionInfoEx;
    bool bRet = false;
    LPTSTR ppBuffer = NULL;
    DWORD dwBytesReturned = 0;
    LONG dwFlags = 0;
    WTSQuerySessionInformation pWTSQuerySessionInformation = NULL;
    WTSFreeMemory pWTSFreeMemory = NULL;

    HMODULE hLib = LoadLibrary( _T("wtsapi32.dll") );
    if (!hLib) 
        return false;
    
    pWTSQuerySessionInformation = (WTSQuerySessionInformation)GetProcAddress(hLib, "WTSQuerySessionInformationW" );
    if (!pWTSQuerySessionInformation) 
        goto EXIT;
    

    pWTSFreeMemory = (WTSFreeMemory)GetProcAddress(hLib, "WTSFreeMemory" );
    if (pWTSFreeMemory == NULL) 
        goto EXIT;
    

    if(pWTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, g_dwSessionID, wtsic, &ppBuffer, &dwBytesReturned)) 
        if(dwBytesReturned > 0) 
            pInfo =  (WTSINFOEXW*)ppBuffer; 
            if (pInfo->Level == 1) 
                dwFlags = pInfo->Data.WTSInfoExLevel1.SessionFlags;
            
            if (dwFlags == WTS_SESSIONSTATE_LOCK) 
                bRet = true;
            
        
        pWTSFreeMemory(ppBuffer);
        ppBuffer = NULL;
    
EXIT:
    if (hLib != NULL) 
        FreeLibrary(hLib);
    
    return bRet;

请查看以下文章了解 WTSINFOEX 结构支持的平台: https://technet.microsoft.com/ru-ru/sysinternals/ee621017

【讨论】:

DW_WTSSessionInfoEx 的定义在哪里?【参考方案2】:

从你给的same MSDN link,“备注”第三段说:

此功能与按 Ctrl+Alt+Del 并单击锁定工作站的结果相同。要解锁工作站,用户必须登录。您不能调用任何函数来确定工作站是否被锁定。要在用户登录时接收通知,请使用 WTSRegisterSessionNotification 函数接收 WM_WTSSESSION_CHANGE 消息. 您可以使用会话通知来跟踪桌面状态,以便了解是否可以与用户进行交互。

【讨论】:

【参考方案3】:

Alex Vershynin 的版本运行良好,但我必须进行一些代码更改。

我必须:将 DW_WTSSessionInfoEx 更改为 WTSSessionInfoEx(回答 user586399),将“g_dwSessionID”定义为 WTSGetActiveConsoleSessionId(),包括 Wtsapi32.h。我想就是这样……

由于无法评论,我将整个代码粘贴在这里。

#include "Wtsapi32.h"
bool IsSessionLocked()

    typedef BOOL( PASCAL * WTSQuerySessionInformation )( HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR* ppBuffer, DWORD* pBytesReturned );
    typedef void ( PASCAL * WTSFreeMemory )( PVOID pMemory );

    WTSINFOEXW * pInfo = NULL;
    WTS_INFO_CLASS wtsic = WTSSessionInfoEx;
    bool bRet = false;
    LPTSTR ppBuffer = NULL;
    DWORD dwBytesReturned = 0;
    LONG dwFlags = 0;
    WTSQuerySessionInformation pWTSQuerySessionInformation = NULL;
    WTSFreeMemory pWTSFreeMemory = NULL;

    HMODULE hLib = LoadLibrary( "wtsapi32.dll" );
    if( !hLib )
    
        return false;
    
    pWTSQuerySessionInformation = (WTSQuerySessionInformation) GetProcAddress( hLib, "WTSQuerySessionInformationW" );
    if( pWTSQuerySessionInformation )
    
        pWTSFreeMemory = (WTSFreeMemory) GetProcAddress( hLib, "WTSFreeMemory" );
        if( pWTSFreeMemory != NULL )
        
            DWORD dwSessionID = WTSGetActiveConsoleSessionId();
            if( pWTSQuerySessionInformation( WTS_CURRENT_SERVER_HANDLE, dwSessionID, wtsic, &ppBuffer, &dwBytesReturned ) )
            
                if( dwBytesReturned > 0 )
                
                    pInfo = (WTSINFOEXW*) ppBuffer;
                    if( pInfo->Level == 1 )
                    
                        dwFlags = pInfo->Data.WTSInfoExLevel1.SessionFlags;
                    
                    if( dwFlags == WTS_SESSIONSTATE_LOCK )
                    
                        bRet = true;
                    
                
                pWTSFreeMemory( ppBuffer );
                ppBuffer = NULL;
            
        
    
    if( hLib != NULL )
    
        FreeLibrary( hLib );
    
    return bRet;

【讨论】:

【参考方案4】:

正如对 MGamsby 帖子的改进:如果你的目标是 Win8.1 SDK 或 Win10 SDK,那么就没有必要乱搞 GetProcAddress()、LoadLibrary() 和 WTSGetActiveConsoleSessionId(),而且代码变得很多更紧凑:

bool isSessionLocked()

    WTSINFOEXW* pInfo = NULL;
    WTS_INFO_CLASS wtsic = WTSSessionInfoEx;
    LPTSTR ppBuffer = NULL;
    DWORD dwBytesReturned = 0;
    LONG sessionFlags = WTS_SESSIONSTATE_UNKNOWN; // until we know otherwise. Prevents a false positive since WTS_SESSIONSTATE_LOCK == 0

    DWORD dwSessionID = WTSGetActiveConsoleSessionId();

    if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, dwSessionID, wtsic, &ppBuffer, &dwBytesReturned))
    
        if (dwBytesReturned > 0)
        
            pInfo = (WTSINFOEXW*)ppBuffer;
            if (pInfo->Level == 1)
            
                sessionFlags = pInfo->Data.WTSInfoExLevel1.SessionFlags;
            
        
        WTSFreeMemory(ppBuffer);
        ppBuffer = NULL;
    

    return (sessionFlags == WTS_SESSIONSTATE_LOCK);

注意: 我知道问题是关于 Windows 7,但您仍然可以使用 Win8.1 SDK 定位 Win7,并且它可用于 VS2015 及更高版本。

编辑:糟糕。我刚刚意识到 OP 要求从 WinXP 开始,在这种情况下,是的,你确实需要弄乱 LoadLibrary() 等。对此感到抱歉。 我会把我的代码留在这里,以防它对任何人有用。

【讨论】:

经过一些更改后,这对我有用:- SessionFlags 是一个位集,因此我需要使用 sessionFlags 和 WTS_SESSIONSTATE_LOCK 来解释该值。在上面的示例中,它的工作方式不可靠。 - 在 Windows 7 上,由于错误,这些值被颠倒了。见docs.microsoft.com/en-us/windows/win32/api/wtsapi32/… 我认为将其解释为位掩码是不正确的,Malte。文档说它可以是 WTS_SESSIONSTATE_UNKNOWN (4294967295 (0xFFFFFFFF))、WTS_SESSIONSTATE_LOCK (0 (0x0)) 或 WTS_SESSIONSTATE_UNLOCK (1 (0x1)) 中的“一个或多个”如果您将其解释为位掩码,那么您的代码会将 WTS_SESSIONSTATE_UNKNOWN 解释为两者WTS_SESSIONSTATE_UNLOCK 和 WTS_SESSIONSTATE_LOCK,我认为这不是你想要的!

以上是关于C++:检查计算机是不是被锁定的主要内容,如果未能解决你的问题,请参考以下文章

C++中的多线程,只检查信号量是不是被锁定

确定计算机是不是被锁定

以下 C++ 代码中实现的 DCL(双重检查锁定)是不是是线程安全的?

双重检查和锁定模式是不是适用于 C++(不是 11)?

检查文件是不是被进程文件句柄锁定

PHP检查文件是不是被flock()锁定?