如何在代码中确定机器锁定的时间?
欢迎使用C#以外的其他创意.
我喜欢Windows服务理念(并已接受它)以简化和清洁,但不幸的是,我不认为它在这种特殊情况下对我有用.我想在我的工作站上运行这个,而不是在家里(或者除了家庭之外,我想),但它被国防部严格控制了.实际上,这就是我自己滚动的部分原因.
无论如何我会写下来看看它是否有效.感谢大家!
我之前没有找到过这个,但是从任何应用程序都可以连接SessionSwitchEventHandler.显然你的应用程序需要运行,但只要它是:
Microsoft.Win32.SystemEvents.SessionSwitch += new Microsoft.Win32.SessionSwitchEventHandler(SystemEvents_SessionSwitch); void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e) { if (e.Reason == SessionSwitchReason.SessionLock) { //I left my desk } else if (e.Reason == SessionSwitchReason.SessionUnlock) { //I returned to my desk } }
我将创建一个处理OnSessionChange事件的Windows服务(visual studio 2005项目类型),如下所示:
protected override void OnSessionChange(SessionChangeDescription changeDescription) { if (changeDescription.Reason == SessionChangeReason.SessionLock) { //I left my desk } else if (changeDescription.Reason == SessionChangeReason.SessionUnlock) { //I returned to my desk } }
您在此时记录活动的内容和方式取决于您,但Windows服务可以快速方便地访问Windows事件,如启动,关闭,登录/退出以及锁定和解锁事件.
下面的解决方案使用Win32 API.在工作站被锁定时调用OnSessionLock,并在解锁时调用OnSessionUnlock.
[DllImport("wtsapi32.dll")] private static extern bool WTSRegisterSessionNotification(IntPtr hWnd, int dwFlags); [DllImport("wtsapi32.dll")] private static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd); private const int NotifyForThisSession = 0; // This session only private const int SessionChangeMessage = 0x02B1; private const int SessionLockParam = 0x7; private const int SessionUnlockParam = 0x8; protected override void WndProc(ref Message m) { // check for session change notifications if (m.Msg == SessionChangeMessage) { if (m.WParam.ToInt32() == SessionLockParam) OnSessionLock(); // Do something when locked else if (m.WParam.ToInt32() == SessionUnlockParam) OnSessionUnlock(); // Do something when unlocked } base.WndProc(ref m); return; } void OnSessionLock() { Debug.WriteLine("Locked..."); } void OnSessionUnlock() { Debug.WriteLine("Unlocked..."); } private void Form1Load(object sender, EventArgs e) { WTSRegisterSessionNotification(this.Handle, NotifyForThisSession); } // and then when we are done, we should unregister for the notification // WTSUnRegisterSessionNotification(this.Handle);
我知道这是一个老问题,但是我找到了一种获取给定会话的锁定状态的方法。
我在这里找到了答案,但是它是用C ++编写的,所以我尽可能地将其翻译为C#以获取“锁定状态”。
因此,这里去:
static class SessionInfo { 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; static SessionInfo() { var os_version = Environment.OSVersion; _is_win7 = (os_version.Platform == PlatformID.Win32NT && os_version.Version.Major == 6 && os_version.Version.Minor == 1); } [DllImport("wtsapi32.dll")] private 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")] private static extern void WTSFreeMemoryEx( WTS_TYPE_CLASS WTSTypeClass, IntPtr pMemory, UInt32 NumberOfEntries ); private 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 } private 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 } [StructLayout(LayoutKind.Sequential)] private struct WTSINFOEX { public UInt32 Level; public UInt32 Reserved; /* I have observed the Data field is pushed down by 4 bytes so i have added this field as padding. */ public WTSINFOEX_LEVEL Data; } [StructLayout(LayoutKind.Sequential)] private struct WTSINFOEX_LEVEL { public WTSINFOEX_LEVEL1 WTSInfoExLevel1; } [StructLayout(LayoutKind.Sequential)] private struct WTSINFOEX_LEVEL1 { public UInt32 SessionId; public WTS_CONNECTSTATE_CLASS SessionState; public Int32 SessionFlags; /* I can't figure out what the rest of the struct should look like but as i don't need anything past the SessionFlags i'm not going to. */ } public static LockState GetSessionLockState(UInt32 session_id) { IntPtr ppBuffer; UInt32 pBytesReturned; Int32 result = WTSQuerySessionInformation( WTS_CURRENT_SERVER, session_id, WTS_INFO_CLASS.WTSSessionInfoEx, out ppBuffer, out pBytesReturned ); if (result == FALSE) return LockState.Unknown; var session_info_ex = Marshal.PtrToStructure(ppBuffer); if (session_info_ex.Level != 1) return LockState.Unknown; var lock_state = session_info_ex.Data.WTSInfoExLevel1.SessionFlags; WTSFreeMemoryEx(WTS_TYPE_CLASS.WTSTypeSessionInfoLevel1, ppBuffer, pBytesReturned); if (_is_win7) { /* Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ee621019(v=vs.85).aspx * Windows Server 2008 R2 and Windows 7: Due to a code defect, the usage of the WTS_SESSIONSTATE_LOCK * and WTS_SESSIONSTATE_UNLOCK flags is reversed. That is, WTS_SESSIONSTATE_LOCK indicates that the * session is unlocked, and WTS_SESSIONSTATE_UNLOCK indicates the session is locked. * */ 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; } } } }
注意:上面的代码是从一个更大的项目中提取的,所以如果我错过了一点抱歉。我没有时间测试上面的代码,但计划在一两周后回来检查所有内容。我现在才发布它是因为我不想忘记这样做。