On my current project I wanted a way to help maintain our application after deployment.
Sure I have added logging, I have added the ability to email the stack
trace to an email account, but neither of these will tell me exactly
what the user was actually doing at the time of the exception. And my experience
has taught me that if you ask the user what to explain to exactly what
they were doing they will either a) not remember or b) not give you ALL
the details you need.
So in order to help me with this I decided
to implement the ability to take a screen shot of the application when
an exception occurs. Setting this up was actually pretty easy. Below
are the steps needed to implement this in your application.
Steps
- Creating the screen shot library
- Setting up the application to globally listen for unhandeled exceptions
- Taking the screen shot and saving it to disk.
1) Creating the screen shot library
*** NOTE *** I know there are many ways to take a screen shot in .net, this is just one way
Importing methods from gdi32.dll:
[DllImportAttribute( "gdi32.dll" )]
private static extern IntPtr CreateDC(
string lpszDriver, // driver name
string lpszDevice, // device name
string lpszOutput, // not used; should be NULL
IntPtr lpInitData // optional printer data
);
[DllImportAttribute( "gdi32.dll" )]
private static extern bool BitBlt(
IntPtr hdcDest, // handle to destination DC
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
Int32 dwRop // raster operation code
Taking the screen shot:
public static Image ScreenShotAsJPG()
{
IntPtr dc1 = CreateDC( "DISPLAY", null, null, ( IntPtr ) null );
Graphics g1 = Graphics.FromHdc( dc1 );
Image MyImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, g1);
Graphics g2 = Graphics.FromImage( MyImage );
dc1 = g1.GetHdc();
IntPtr dc2 = g2.GetHdc();
BitBlt( dc2, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, dc1, 0, 0, 13369376 );
g1.ReleaseHdc( dc1 );
g2.ReleaseHdc( dc2 );
return MyImage;
}
Saving the screen shot to disk:
public static string SaveScreenShot( Image image)
{
string outputFolder = GetApplicationPath( );
string screenshotFilePath = CreateSaveFileName( outputFolder, 0 );
if ( !Directory.Exists( outputFolder ))
{
Directory.CreateDirectory( outputFolder );
}
image.Save( screenshotFilePath, ImageFormat.Jpeg );
CleanupScreenshots( );
return screenshotFilePath;
}
Wiring up your application to handle Unhandled Exceptions:
This needs to be done in your main startup routine (it is assume that you are using a main() method as your startup)
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler( CurrentDomain_UnhandledException );
The code to take the screen shot
private static void CurrentDomain_UnhandledException( object sender, UnhandledExceptionEventArgs e )
{
ScreenCapture.SaveScreenShot( ScreenCapture.ScreenShotAsJPG() );
// Perform any other logging/clean up needed
}
Well there you have it, a simple way to take a screen shot of your application when an exception occurs.
Let me your thoughts, is there a different/better way?
dp.SyntaxHighlighter.HighlightAll('code');
Posted
11-01-2006 7:04 AM
by
Derik Whittaker