클라이언트 개발 시에 보통 세션 유휴 시간을 지정하여 시간 만료 시 프로그램을 종료하는 기능을 많이 구현한다. 보통 키보드 마우 스 입력이 일정 시간 없거나, 해당 프로그램의 포커스가 일정 시간 벗어난 경우를 조건으로 사용한다. 키보드 마우스의 입력 같은 경우는 키보드,마우스 메시지를 후킹 하여 하는방법도 있지만 대부분의 보안프로그램이 차단하기 때문에 "마지막 키보드 입력 시간을 비교" 하는 방식으로 구현 했고, 프로그램 포커스는 현재 활성화된 프로스세 핸들과 프로세스 아이디를 찾아 비교하는 식으로 구현했다.
마지막 키보드 입력 시간 검사 및 프로세스 비활성화 확인
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
// 1. SessionIdleTimer 생성 (프로젝트 사용 시에는 이미 싱글톤으로 구현 해둠)
// 2. 시간 만료 시 할 동작을 idleTimeExceeded에 등록
// 3. 타이머 시작
// 4. 1초마다 마지막 키보드 입력시간을 가져와 비교, 현재 활성화된 프로세스와 동작중인 프로세스 비교하여 시간 갱신 후 비교
// 5. 지정된 시간 초과 시 종료
namespace Test1234
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SessionIdleTimer sessionIdleTimer = new SessionIdleTimer();
// Timer 만료 시 이벤트를 등록
sessionIdleTimer.idleTimeExceeded += (s, e) =>
{
MessageBox.Show("세션 IDLE Time 만료");
};
sessionIdleTimer.StartTimer(1);
}
}
public class SessionIdleTimer
{
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO
{
public uint cbSize;
public uint dwTime;
}
[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
System.Timers.Timer _sessionIdleTimer = null;
public event EventHandler idleTimeExceeded;
private DateTime _lastActiveTime;
public void StartTimer(int sessionIdleTime, int intervals = 1000)
{
if (_sessionIdleTimer != null) { _sessionIdleTimer.Dispose(); }
_sessionIdleTimer = new System.Timers.Timer();
_sessionIdleTimer.Interval = intervals;
_sessionIdleTimer.Elapsed += (s, e) =>
{
// 프로그램 Activate 시간 갱신
if (IsMyAppForeground()) _lastActiveTime = DateTime.Now;
// 세션 유휴 초과 확인
if (IsIdleMoreThan(TimeSpan.FromMinutes(sessionIdleTime)))
{
_sessionIdleTimer?.Stop();
idleTimeExceeded?.Invoke(this, EventArgs.Empty);
}
};
_sessionIdleTimer.Start();
}
public void EndTimer()
{
_sessionIdleTimer?.Dispose();
idleTimeExceeded = null;
}
// 마지막 키보드 및 마우스 입력 시간
public uint GetIdleMilliseconds()
{
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
if (!GetLastInputInfo(ref lastInputInfo))
return 0;
return (uint)Environment.TickCount - lastInputInfo.dwTime;
}
// 현재 실행 중인 프로세스와 현재 활성화된 프로세스가 동일한지 확인
public bool IsMyAppForeground()
{
IntPtr foregroundHwnd = GetForegroundWindow();
GetWindowThreadProcessId(foregroundHwnd, out uint foregroundPid);
int myPid = Process.GetCurrentProcess().Id;
return foregroundPid == myPid;
}
// 키보드 및 마우스 입력 시간 확인
// 프로세스 비활성화 시간 확인
public bool IsIdleMoreThan(TimeSpan timeSpan)
{
double idleMilliseconds = GetIdleMilliseconds();
TimeSpan idleDuration = DateTime.Now - _lastActiveTime;
return idleMilliseconds >= timeSpan.TotalMilliseconds || idleDuration >= timeSpan;
}
public void Dispose()
{
_sessionIdleTimer?.Dispose();
}
}
}
'프로그래밍 > C# .NET' 카테고리의 다른 글
제네릭 (2) (0) | 2023.04.17 |
---|---|
제네릭 (0) | 2023.04.16 |
C# Invoke, BeginInvoke (0) | 2023.04.02 |
다양한 로그 수집 하기 (0) | 2023.03.27 |
BCL (1) (0) | 2023.03.25 |