Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Monitoring desktop windows from a Windows service

, 2 Jan 2008 CPOL
Capture and save desktop windows from a Windows service.
ScreenMonitor_src.zip
ScreenMonitor
ScreenMonitorLib
Properties
ScreenMonitor
ScreenmonitorService
ScreenmonitorService
SnapShotManager
Properties
Settings.settings
DataSources
ScreenMonitorLib.SnapShotDS+ApplicationsDataTable.datasource
Debug
ScreenMonitorLib.SnapShotDS+SnapShotDataTable.datasource
SnapShotDS.xsc
ScreenMonitorLib
Settings.settings
SnapShotDS.xss
Release
Release
ScreenMonitorLib.SnapShotDS+WndSettingsDataTable.datasource
SetupMonitor
SetupMonitor.vdproj
Properties
Debug
screenmonitor_src2.zip
Settings.settings
ScreenMonitorLib.SnapShotDS+ApplicationsDataTable.datasource
ScreenMonitorLib.SnapShotDS+SnapShotDataTable.datasource
SnapShotDS.xsc
Settings.settings
SnapShotDS.xss
ScreenMonitorLib.SnapShotDS+WndSettingsDataTable.datasource
SetupMonitor.vdproj
SetupMonitor_msi.zip
SetupMonitor.msi
setupmonitor_msi2.zip
SetupMonitor.msi
/*
 * 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);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

dmihailescu
Software Developer (Senior)
United States United States
Decebal Mihailescu is a software engineer with interest in .Net, C# and C++.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 2 Jan 2008
Article Copyright 2007 by dmihailescu
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid