使用透明的点击表单来监控活动

时间:2015-08-17 15:44:50

标签: c# .net winforms winforms-interop

客户遇到问题,员工打开显示敏感信息的程序,并在不关闭的情况下离开。他们要求我监控应用程序何时打开,并在一定程度的不活动后关闭它。

我所做的是创建了一个新程序,它启动原始程序,但另一个表单就在它之上。如果我的表单是透明的,我可以毫无问题地点击表单,并操纵底层程序。如果我的表单(略微)不透明,点击将注册我的程序,但不会通过。

我需要的是一种方法,让我的表单注册发生了点击,重置其计时器,并将点击传递给底层应用程序。我可以重置计时器,或者我可以通过点击,但不能同时通过。

这是我正在尝试的代码。第一部分将我的表单定义为透明,并将其保存在另一个应用程序之上。

    private void Form1_Load(object sender, EventArgs e)
    {
        this.Opacity = 0.40;
        this.TopMost = true;
    }

我认为这会让我监视点击,重置计时器,然后通过它,但它不起作用,所以我必须遗漏一些东西。编辑:WT_NCHITTEST = 0x84,HTTRANSPARENT = -1,如下所示:https://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_NCHITTEST) // m.Msg 0x84 means that Windows is asking our form whether it is "transparent" or not.
        {
            timeToClose = 10;
            m.Result = new IntPtr(HTTRANSPARENT); // tell Windows yes, to pass everything through.
        }

        base.WndProc(ref m);
    } 

1 个答案:

答案 0 :(得分:2)

这是过度设计,我使用System.Timers.Timer和PInvoke GetLastInputInfo实现不活动检查。运行第二个应用程序,监视工作站不活动状态,并在违反阈值时关闭敏感应用程序。

以一定间隔初始化定时器并将其设置为自动重置,然后在每次定时器过去时检查是否不活动。如果不活动时间大于阈值,请将其关闭。

以下是GetLastInputInfo的代码。

public static class Tracker
{
    /// <summary>
    /// Reference to the GetLastInputInfo in the user32.dll file.
    /// </summary>
    /// <param name="plii">LASTINPUTINFO struct</param>
    /// <returns></returns>
    [DllImport("user32.dll")]
    private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

    /// <summary>
    /// Polls the system for the milliseconds elapsed since last user input.
    /// </summary>
    /// <returns>Milliseconds since last user input.</returns>
    public static uint GetIdleTime()
    {
        LASTINPUTINFO lastInput = new LASTINPUTINFO();
        lastInput.cbSize = (uint)Marshal.SizeOf(lastInput);
        GetLastInputInfo(ref lastInput);

        return ((uint)Environment.TickCount - lastInput.dwTime);
    }
}

/// <summary>
/// Struct required and populated by the user32.dll GetLastInputInfo method.
/// </summary>
internal struct LASTINPUTINFO
{
    public uint cbSize; //Size of the struct.
    public uint dwTime; //TickCount at last input.
}

我的不活动计时器实现如下所示:

public void InitializeTimer()
{
    ActivityTimer = new System.Timers.Timer(Configuration.TimeoutSettings["IntervalMilliseconds"]);
    ActivityTimer.AutoReset = true;
    ActivityTimer.Elapsed += OnElapsedPollForActivity;
    ActivityTimer.Start();
}

/// <summary>
/// Method is called in ValidationForm_FormClosing, unsubscribes handler from event and stops the clock.
/// </summary>
public void TerminateTimer()
{
    ActivityTimer.Elapsed -= OnElapsedPollForActivity;
    ActivityTimer.Stop();
}

/// <summary>
/// Fires on ActivityTimer.Elapsed, polls workstation for time since last user input.
/// </summary>
private void OnElapsedPollForActivity(object sender, System.Timers.ElapsedEventArgs e)
{
    if (Tracker.GetIdleTime() > Configuration.TimeoutSettings["TriggerMilliseconds"])
    {
        Logger.LogException(CurrentSession.SessionID, DateTime.Now, new InactivityException("Detected extended period of workstation inactivity."));
        Application.Exit();
    }
}