/*
* Please leave this Copyright notice in your code if you use it
* Written by Decebal Mihailescu [http://www.codeproject.com/script/articles/list_articles.asp?userid=634640]
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using Microsoft.Win32;
using System.Threading;
using System.Reflection;
using System.Configuration;
using ScreenMonitorLib;
using System.Security.Principal;
using System.Runtime.InteropServices;
using WndList = System.Collections.Generic.List<System.IntPtr>;
namespace ScreenmonitorService
{
enum SystemCategory : short
{
None = 0,
Devices,
Disk,
Printers,
Services,
Shell,
SystemEvent,
Network
}
enum RunAs : uint
{
Service = 0,
Process
}
public partial class ScreenMonitor : ServiceBase
{
static ManualResetEvent _desktopUnLocked = new ManualResetEvent(true);
static ManualResetEvent _terminate= new ManualResetEvent(false);
static ImpersonateInteractiveUser _imptst = null;
public Thread workerThread = null;
public static readonly TimeSpan _interval;
static private bool _blocked = false;
static ScreenMonitor()
{
AppSettingsReader reader = new AppSettingsReader();
int interval = (int)reader.GetValue("interval", typeof(int));
_interval = new TimeSpan(interval / 3600, (interval / 60) % 60, interval % 60);
}
public ScreenMonitor()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
IntPtr handle = this.ServiceHandle;
if ((workerThread == null) ||
((workerThread.ThreadState &
(System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Stopped)) != 0))
{
workerThread = new Thread(new ParameterizedThreadStart(DoWork));
workerThread.Start(this);
}
if (workerThread != null)
{
}
}
public void DoWork(object data)
{
try
{
StartNewDesktopSession();
string folder = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\";
ScreenMonitorLib.SnapShot snp = new ScreenMonitorLib.SnapShot(folder, _interval, this.ServiceHandle);
bool bexit = false;
do
{
bexit = _terminate.WaitOne(_interval, false);
_desktopUnLocked.WaitOne();
if(_blocked)
{
_blocked = false;
// EventLog.WriteEntry("Screen Monitor", string.Format("_desktopUnLocked signaled at {0:T}", DateTime.Now.TimeOfDay), EventLogEntryType.Information, 1, 1);
continue;
}
WndList lst = snp.GetDesktopWindows(_imptst.HDesktop);
snp.SaveAllSnapShots(lst);
}
while (!bexit);
}
catch (ApplicationException ex)
{
EventLog.WriteEntry("Screen Monitor", string.Format("ApplicationException: {0}\n at {1}", ex.Message, ex.InnerException.TargetSite), EventLogEntryType.Error, 1, 1);
}
catch (Exception ex)
{
EventLog.WriteEntry("Screen Monitor", string.Format("exception in thread at: {0}:{1}", ex.TargetSite.Name, ex.Message), EventLogEntryType.Error, 1, 1);
}
finally
{
if (_imptst != null)
_imptst.Dispose();
}
}
/// <summary>
/// OnStop: Put your stop code here
/// - Stop threads, set final data, etc.
/// </summary>
protected override void OnStop()
{
try
{
_terminate.Set();
_desktopUnLocked.Set();
workerThread.Join(_interval);
base.OnStop();
}
catch (Exception ex)
{
EventLog.WriteEntry("Screen Monitor", "exception in OnStop:" + ex.Message, EventLogEntryType.Error, 1, 1);
}
}
/// <summary>
/// OnPause: Put your pause code here
/// - Pause working threads, etc.
/// </summary>
protected override void OnPause()
{
base.OnPause();
}
/// <summary>
/// OnContinue: Put your continue code here
/// - Un-pause working threads, etc.
/// </summary>
protected override void OnContinue()
{
base.OnContinue();
}
/// <summary>
/// OnShutdown(): Called when the System is shutting down
/// - Put code here when you need special handling
/// of code that deals with a system shutdown, such
/// as saving special data before shutdown.
/// </summary>
protected override void OnShutdown()
{
base.OnShutdown();
}
/// <summary>
/// OnCustomCommand(): If you need to send a command to your
/// service without the need for Remoting or Sockets, use
/// this method to do custom methods.
/// </summary>
/// <param name="command">Arbitrary Integer between 128 & 256</param>
protected override void OnCustomCommand(int command)
{
// A custom command can be sent to a service by using this method:
//# int command = 128; //Some Arbitrary number between 128 & 256
//# ServiceController sc = new ServiceController("NameOfService");
//# sc.ExecuteCommand(command);
base.OnCustomCommand(command);
}
/// <summary>
/// OnPowerEvent(): Useful for detecting power status changes,
/// such as going into Suspend mode or Low Battery for laptops.
/// </summary>
/// <param name="powerStatus">The Power Broadcase Status (BatteryLow, Suspend, etc.)</param>
protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
{
return base.OnPowerEvent(powerStatus);
}
/// <summary>
/// OnSessionChange(): To handle a change event from a Terminal Server session.
/// Useful if you need to determine when a user logs in remotely or logs off,
/// or when someone logs into the console.
/// </summary>
/// <param name="changeDescription"></param>
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
switch (changeDescription.Reason)
{
case SessionChangeReason.SessionUnlock:
case SessionChangeReason.SessionLogon:
{
StartNewDesktopSession();
_desktopUnLocked.Set();
}
break;
case SessionChangeReason.SessionLock:
case SessionChangeReason.SessionLogoff:
_blocked = true;
_desktopUnLocked.Reset();
break;
default:
break;
}
//EventLog.WriteEntry("Screen Monitor", string.Format("OnSessionChange reason: {0} session id: {1} at {2:T}",
// changeDescription.Reason, changeDescription.SessionId ,DateTime.Now.TimeOfDay), EventLogEntryType.SuccessAudit, 1, 1);
base.OnSessionChange(changeDescription);
}
private static void StartNewDesktopSession()
{
Process[] plst = Process.GetProcessesByName("explorer");
while (plst.Length == 0)
{
Thread.Sleep(Convert.ToInt32(_interval.TotalMilliseconds));
plst = Process.GetProcessesByName("explorer");
}
if(_imptst != null)
_imptst.Dispose();
_imptst = new ImpersonateInteractiveUser(plst[0], false);
}
}
}