如何在C#中检测Windows的当前状态(解锁/锁定)

4
如何在C#中检测Windows的当前状态(已解锁/已锁定)?我找到的所有示例都涉及由Windows解锁或锁定触发的事件处理程序。我不感兴趣的是事件处理程序。(对于加粗表示抱歉。)我只想知道Windows的当前状态(已解锁或已锁定)。我找到的最接近的方法是提到System.Security.Principal.WindowsIdentity.GetCurrent(),但我不知道如何使用它。
对于我的特定代码的解决方法是,如果有一个函数可以调用并返回IsGUIViewable,则可以绕过此问题。但是,如果可能的话,我仍然希望得到原始问题的答案。

2
你就是找不到,别再找了。 - Hans Passant
处理当Windows被锁定或解锁时触发的事件处理程序。我不想在Windows被锁定或解锁时触发任何东西。我只需要当前状态。请仔细阅读我的问题。 - Sean
这篇帖子说你可以使用OpenInputDesktop,但听起来对我来说有点像黑客行为... https://code.msdn.microsoft.com/windowsapps/CSDetectWindowsSessionState-f27d0321 - Jay
1
你为什么认为有一个可以检查的状态?你为什么认为首先在用户GUI会话中运行?同一台机器上的其他会话呢,如果它们被锁定了,会让你感到困扰吗?你为什么首先关心这个问题?如果你知道事件处理程序,为什么不自己维护状态? - Luaan
@JasonEvans 谢谢,但是对于那个问题的唯一答案是用C++编写的,并且我不知道在C#中相应的函数。 - Sean
显示剩余8条评论
1个回答

1
我也曾经遇到过同样的问题。在这种情况下,我使用了SystemEvents.SessionSwitch,但是这段代码直到用户改变会话后才有用。在观察了许多帖子之后,下面是可行的代码。
定义您的本机Enum类:
"NativeEnums.cs"
public enum WTS_INFO_CLASS
{
    WTSInitialProgram = 0,
    WTSApplicationName = 1,
    WTSWorkingDirectory = 2,
    WTSOEMId = 3,
    WTSSessionId = 4,
    WTSUserName = 5,
    WTSWinStationName = 6,
    WTSDomainName = 7,
    WTSConnectState = 8,
    WTSClientBuildNumber = 9,
    WTSClientName = 10,
    WTSClientDirectory = 11,
    WTSClientProductId = 12,
    WTSClientHardwareId = 13,
    WTSClientAddress = 14,
    WTSClientDisplay = 15,
    WTSClientProtocolType = 16,
    WTSIdleTime = 17,
    WTSLogonTime = 18,
    WTSIncomingBytes = 19,
    WTSOutgoingBytes = 20,
    WTSIncomingFrames = 21,
    WTSOutgoingFrames = 22,
    WTSClientInfo = 23,
    WTSSessionInfo = 24,
    WTSSessionInfoEx = 25,
    WTSConfigInfo = 26,
    WTSValidationInfo = 27,
    WTSSessionAddressV4 = 28,
    WTSIsRemoteSession = 29
}

public enum WTS_TYPE_CLASS
{
    WTSTypeProcessInfoLevel0,
    WTSTypeProcessInfoLevel1,
    WTSTypeSessionInfoLevel1
}

public enum WTS_CONNECTSTATE_CLASS
{
    WTSActive,
    WTSConnected,
    WTSConnectQuery,
    WTSShadow,
    WTSDisconnected,
    WTSIdle,
    WTSListen,
    WTSReset,
    WTSDown,
    WTSInit
}

public enum LockState
{
    Unknown,
    Locked,
    Unlocked
}

以下是相关的结构体:

public class NativeStructs
{
    [StructLayout(LayoutKind.Sequential)]
    public struct WTSINFOEX
    {
        public UInt32 Level;
        public UInt32 Reserved;
        public WTSINFOEX_LEVEL Data;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct WTSINFOEX_LEVEL
    {
        public WTSINFOEX_LEVEL1 WTSInfoExLevel1;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct WTSINFOEX_LEVEL1
    {
        public UInt32 SessionId;
        public WTS_CONNECTSTATE_CLASS SessionState;
        public Int32 SessionFlags;
    }
}

定义您的本地方法:

public class NativeMethods
{
    [DllImport("wtsapi32.dll")]
    public static extern Int32 WTSQuerySessionInformation(IntPtr hServer, [MarshalAs(UnmanagedType.U4)] UInt32 SessionId, [MarshalAs(UnmanagedType.U4)] WTS_INFO_CLASS WTSInfoClass, out IntPtr ppBuffer, [MarshalAs(UnmanagedType.U4)] out UInt32 pBytesReturned);

    [DllImport("wtsapi32.dll")]
    public static extern void WTSFreeMemoryEx(WTS_TYPE_CLASS WTSTypeClass, IntPtr pMemory, UInt32 NumberOfEntries);

    [DllImport("kernel32.dll")]
    public static extern uint WTSGetActiveConsoleSessionId();
}

现在定义您的 API 控制器类:

public sealed class SessionManager
{
    private static readonly Lazy<SessionManager> _sessionManager = new Lazy<SessionManager>(() => new SessionManager());
    private const Int32 FALSE = 0;

    private static readonly IntPtr WTS_CURRENT_SERVER = IntPtr.Zero;
    private const Int32 WTS_SESSIONSTATE_LOCK = 0;
    private const Int32 WTS_SESSIONSTATE_UNLOCK = 1;

    private static bool _is_win7 = false;

    public static SessionManager GetInstance()
    {
        return _sessionManager.Value;
    }

    public UInt32 GetSessionId()
    {
        UInt32 result = 0;
        result = NativeMethods.WTSGetActiveConsoleSessionId();
        if (result == 0xFFFFFFFF)
        {
            App.LOG(LogLevel.Standard, "No session attached to the physical console.");
        }   

        return result;
    }

    public LockState GetSessionLockState()
    {
        try
        {
            IntPtr ppBuffer;
            UInt32 pBytesReturned;

            UInt32 session_id = GetSessionId();
            Int32 result = NativeMethods.WTSQuerySessionInformation(WTS_CURRENT_SERVER, session_id, WTS_INFO_CLASS.WTSSessionInfoEx, out ppBuffer, out pBytesReturned);

            if (result == FALSE)
                return LockState.Unknown;

            if (pBytesReturned > 0)
            {
                var session_info_ex = Marshal.PtrToStructure<NativeStructs.WTSINFOEX>(ppBuffer);

                if (session_info_ex.Level != 1)
                    return LockState.Unknown;

                var lock_state = session_info_ex.Data.WTSInfoExLevel1.SessionFlags;
                NativeMethods.WTSFreeMemoryEx(WTS_TYPE_CLASS.WTSTypeSessionInfoLevel1, ppBuffer, pBytesReturned);

                var os_version = Environment.OSVersion;
                _is_win7 = (os_version.Platform == PlatformID.Win32NT && os_version.Version.Major == 6 && os_version.Version.Minor == 1);
                if (_is_win7)
                {
                    /* Due to a code defect,Session state logic is revers to upper windows version */
                    switch (lock_state)
                    {
                        case WTS_SESSIONSTATE_LOCK:
                            return LockState.Unlocked;

                        case WTS_SESSIONSTATE_UNLOCK:
                            return LockState.Locked;

                        default:
                            return LockState.Unknown;
                    }
                }
                else
                {
                    switch (lock_state)
                    {
                        case WTS_SESSIONSTATE_LOCK:
                            return LockState.Locked;

                        case WTS_SESSIONSTATE_UNLOCK:
                            return LockState.Unlocked;

                        default:
                            return LockState.Unknown;
                    }
                }
            }
            else
            {
                return LockState.Unknown;
            }
        }
        catch(Exception ex)
        {
            App.LOG(LogLevel.Standard, $"[Exception] : {ex.ToString()}");
            return LockState.Unknown;
        }
    }
}

现在从你需要的类中调用这个方法:

LockState lockState = SessionManager.GetInstance().GetSessionLockState();

            LOG(LogLevel.Standard, $"PC screen lock: {lockState.ToString()}");

            if (lockState == LockState.Locked)
            {
                //Writedown lock screen logic here....
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接