C# 以编程方式确定锁定工作站的持续时间?
如何用代码确定机器锁定的时间 C#之外的其他想法也很受欢迎C# 以编程方式确定锁定工作站的持续时间?,c#,windows,C#,Windows,如何用代码确定机器锁定的时间 C#之外的其他想法也很受欢迎 为了简单和干净,我喜欢windows服务的想法(并接受了它),但不幸的是,我认为它在这种特殊情况下不适合我。我想在我的工作站上运行这个程序,而不是在家里(或者在家之外,我想),但由于国防部的原因,它被很难锁定。事实上,这也是我自己滚动的部分原因 不管怎样,我会把它写下来,看看它是否有效。谢谢大家 下面是查找电脑是否锁定的100%工作代码 使用此选项之前,请使用命名空间System.Runtime.InteropServices [Dl
为了简单和干净,我喜欢windows服务的想法(并接受了它),但不幸的是,我认为它在这种特殊情况下不适合我。我想在我的工作站上运行这个程序,而不是在家里(或者在家之外,我想),但由于国防部的原因,它被很难锁定。事实上,这也是我自己滚动的部分原因
不管怎样,我会把它写下来,看看它是否有效。谢谢大家 下面是查找电脑是否锁定的100%工作代码 使用此选项之前,请使用命名空间
System.Runtime.InteropServices
[DllImport("user32", EntryPoint = "OpenDesktopA", CharSet = CharSet.Ansi,SetLastError = true, ExactSpelling = true)]
private static extern Int32 OpenDesktop(string lpszDesktop, Int32 dwFlags, bool fInherit, Int32 dwDesiredAccess);
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern Int32 CloseDesktop(Int32 hDesktop);
[DllImport("user32", CharSet = CharSet.Ansi,SetLastError = true,ExactSpelling = true)]
private static extern Int32 SwitchDesktop(Int32 hDesktop);
public static bool IsWorkstationLocked()
{
const int DESKTOP_SWITCHDESKTOP = 256;
int hwnd = -1;
int rtn = -1;
hwnd = OpenDesktop("Default", 0, false, DESKTOP_SWITCHDESKTOP);
if (hwnd != 0)
{
rtn = SwitchDesktop(hwnd);
if (rtn == 0)
{
// Locked
CloseDesktop(hwnd);
return true;
}
else
{
// Not locked
CloseDesktop(hwnd);
}
}
else
{
// Error: "Could not access the desktop..."
}
return false;
}
我将创建一个处理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);
我以前没有发现过这个,但从任何应用程序都可以连接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
}
}
我知道这是一个老问题,但我找到了一种方法来获取给定会话的锁定状态 我找到了答案,但它是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<WTSINFOEX>(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;
}
}
}
}
静态类SessionInfo{
private const Int32 FALSE=0;
私有静态只读IntPtr WTS_CURRENT_SERVER=IntPtr.Zero;
private const Int32 WTS_SESSIONSTATE_LOCK=0;
private const Int32 WTS_SESSIONSTATE_UNLOCK=1;
私有静态bool_为_win7=false;
静态SessionInfo(){
var os_version=Environment.OSVersion;
_is_win7=(os_version.PlatformID.Win32NT&&os_version.version.Major==6&&os_version.version.Minor==1);
}
[DllImport(“wtsapi32.dll”)]
私有静态外部Int32 WTSQuerySessionInformation(
IntPtr服务器,
[Marshallas(UnmanagedType.U4)]UInt32会话ID,
[Marshallas(UnmanagedType.U4)]WTS\u INFO\u类WTSInfoClass,
输出IntPtr ppBuffer,
[Marshallas(UnmanagedType.U4)]输出UInt32字节返回
);
[DllImport(“wtsapi32.dll”)]
私有静态外部无效WTSFreeMemoryEx(
水处理系统类型水处理系统等级水处理系统等级,
IntPtr存储器,
UInt32条目数
);
私有枚举WTS_信息_类{
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
}
私有枚举WTS_类型_类{
WTSTypeProcessInfoLevel0,
WTSTypeProcessInfoLevel1,
WTSTypeSessionInfoLevel1
}
公共枚举WTS_连接状态_类{
是的,
WTS连接,
WTSConnectQuery,
WTSShadow,
WTS断开连接,
西德尔,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
公共枚举锁状态{
不详,
锁定,
解锁
}
[StructLayout(LayoutKind.Sequential)]
私有结构WTSINFOEX{
公共UInt32级;
public UInt32 Reserved;/*我观察到数据字段向下压了4个字节,所以我添加了这个字段作为填充*/
公共WTSINFOEX_级数据;
}
[StructLayout(LayoutKind.Sequential)]
私有结构WTSINFOEX_级别{
公共水处理厂1级水处理厂1级水处理厂;
}
[StructLayout(LayoutKind.Sequential)]
私有结构WTSINFOEX_LEVEL1{
公共UInt32会话ID;
公共WTS_CONNECTSTATE_类会话状态;
公共Int32会话标志;
/*我不知道结构的其余部分应该是什么样子,但由于我不需要任何超过SessionFlags的内容,所以我不打算这样做*/
}
公共静态锁状态GetSessionLockState(UInt32会话id){
IntPtr-ppBuffer;
UInt32字节返回;
Int32结果=WTSQuerySessionInformation(
WTS_当前_服务器,
会话id,
WTS_INFO_CLASS.WTSSessionInfoEx,
在缓冲区外,
外字节返回
);
如果(结果==FALSE)
返回锁定状态。未知;
var session_info_ex=Marshal.PtrToStructure(ppBuffer);
如果(会话信息前级!=1)
返回锁定状态。未知;
var lock_state=session_info_ex.Data.WTSInfoExLevel1.SessionFlags;
WTSFreeMemoryEx(WTS_TYPE_CLASS.WTSTypeSessionInfoLevel1,ppBuffer,PBytes返回);
如果(_是_win7){
/*参考:https://msdn.microsoft.com/en-us/library/windows/desktop/ee621019(v=vs.85).aspx
*Windows Server 2008 R2和Windows 7:由于代码缺陷,WTS_会话状态_锁的使用
*WTS_SESSIONSTATE_UNLOCK标志被反转。也就是说,WTS_SESSIONSTATE_LOCK表示
CanHandleSessionChangeEvent = true;
public interface IMyServiceContract
{
void Start();
void Stop();
void SessionChanged(Topshelf.SessionChangedArguments args);
}
public class MyService : IMyServiceContract
{
public void Start()
{
}
public void Stop()
{
}
public void SessionChanged(SessionChangedArguments e)
{
Console.WriteLine(e.ReasonCode);
}
}
IMyServiceContract myServiceObject = new MyService(); /* container.Resolve<IMyServiceContract>(); */
HostFactory.Run(x =>
{
x.Service<IMyServiceContract>(s =>
{
s.ConstructUsing(name => myServiceObject);
s.WhenStarted(sw => sw.Start());
s.WhenStopped(sw => sw.Stop());
s.WhenSessionChanged((csm, hc, chg) => csm.SessionChanged(chg)); /* THIS IS MAGIC LINE */
});
x.EnableSessionChanged(); /* THIS IS MAGIC LINE */
/* use command line variables for the below commented out properties */
/*
x.RunAsLocalService();
x.SetDescription("My Description");
x.SetDisplayName("My Display Name");
x.SetServiceName("My Service Name");
x.SetInstanceName("My Instance");
*/
x.StartManually(); // Start the service manually. This allows the identity to be tweaked before the service actually starts
/* the below map to the "Recover" tab on the properties of the Windows Service in Control Panel */
x.EnableServiceRecovery(r =>
{
r.OnCrashOnly();
r.RestartService(1); ////first
r.RestartService(1); ////second
r.RestartService(1); ////subsequents
r.SetResetPeriod(0);
});
x.DependsOnEventLog(); // Windows Event Log
x.UseLog4Net();
x.EnableShutdown();
x.OnException(ex =>
{
/* Log the exception */
/* not seen, I have a log4net logger here */
});
});
<package id="log4net" version="2.0.5" targetFramework="net45" />
<package id="Topshelf" version="4.0.3" targetFramework="net461" />
<package id="Topshelf.Log4Net" version="4.0.3" targetFramework="net461" />