📜 ⬆️ ⬇️

Auto Debug Tool

So, imagine a situation. We wrote a program, sent it for testing, the tester finds an error. His actions - creates a letter, describes this error, describes the steps to play, takes a screenshot, attaches a screenshot to the letter, sends it to you.

Let's ease his work.

To do this, we need the HotKey class, which will intercept hot key presses and produce shamanism, the MAPI wrapper class, which will immediately bring up a window with a new letter, and the DebugTool class, which will put all the information together and do the work.

')
The HotKey class uses the user32.dll library to register an event for a specific key combination (the RegisterHotKey method), if such a key combination is already registered, then the ApplicationException ("Hotkey already in use") will be thrown.

In the program, we register the event with the Ctrl-Shift-B event OnBugHandle:

public static HotKey hotKey = new HotKey(Keys.B, HotKey.KeyModifiers.Control | HotKey.KeyModifiers.Shift, new EventHandler(OnBugHandle));

where OnBugHandle calls the static DebugTool.ProcessBug () method:

public static void OnBugHandle(object obj, EventArgs args)
{
DebugTool.ProcessBug();
}

Next we move on to the MAPI wrapper class. This class will allow us to create a letter to send to the developer:

We now turn to the main class DebugTool. This class should do the following:



In addition, let's assign a DebugTool to handle the OnUnhandledException event with a record in a separate file of the call stack and the exception itself.

Create a screenshot:
private static void MakeScreenshot()
{
Bitmap Bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
PixelFormat.Format32bppArgb);
Graphics Graphic = Graphics.FromImage(Bitmap);
Graphic.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0, 0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);
Bitmap.Save(tempPath + "screenshot.bmp");
}


TempPath is a temporary folder, it can be queried via Path.GetTempPath (). There we will collect all the files that we need to archive.

Saving to the call stack file:

private static void SaveStack()
{
using (TextWriter textWriter = new StreamWriter(
new FileStream(tempPath + "stack.txt", FileMode.Create, FileAccess.Write),
Encoding.Unicode))
{

StackTrace st = new StackTrace(true);
for (int i = 0; i < st.FrameCount; i++)
{
StackFrame sf = st.GetFrame(i);
textWriter.WriteLine(string.Empty);
textWriter.WriteLine("Method: {0}", sf.GetMethod());
textWriter.WriteLine("Line Number: {0}", sf.GetFileLineNumber());
}
}
}

Saving exception data (with recursive recording of all internal exceptions):

private static void ExceptionInfo(Exception ex)
{
Exception currentException = ex;
using (TextWriter textWriter = new StreamWriter(
new FileStream(tempPath + "exception.txt", FileMode.Create, FileAccess.Write),
Encoding.Unicode))
{

while (currentException != null)
{
textWriter.WriteLine(string.Empty);
textWriter.WriteLine("Message : " + currentException.Message);
textWriter.WriteLine("Stack Trace : " + currentException.StackTrace);
textWriter.WriteLine("Source : " + currentException.Source);
currentException = currentException.InnerException;
}
}
}

Now the error handling itself. Here we first take a screenshot, then copy all the attached files into a temporary folder. Create a zip archive using ZipPackage, and send this archive:

public static void ProcessBug()
{
List files = new List();
tempPath = Path.GetTempPath();
MakeScreenshot();

foreach (string BindFile in BindedFiles)
{
if (File.Exists(BindFile))
{
File.Copy(BindFile, tempPath + Path.GetFileName(BindFile), false);
files.Add(Path.GetFileName(BindFile));
}
}

files.Add(Path.GetFileName("screenshot.bmp"));
using (Package package = ZipPackage.Open(tempPath + "package.zip", FileMode.Create))
{
foreach (string fi in files)
{
Uri partUri = PackUriHelper.CreatePartUri(new Uri(fi, UriKind.Relative));
PackagePart packagePart = package.CreatePart(partUri, MediaTypeNames.Text.Plain);

using (FileStream fileStream = new FileStream(tempPath + fi, FileMode.Open, FileAccess.Read))
{
CopyStream(fileStream, packagePart.GetStream());
}
}
package.Flush();
}

SendPackage(BugMessageSubject, tempPath + "package.zip");

foreach (string fi in files)
{
File.Delete(tempPath + fi);
}
File.Delete(tempPath + "package.zip");
}


SendPackage , zip- :

private static void SendPackage(string MessageSubject, string packageFile)
{
try
{
MAPI mapi = new MAPI();
mapi.AddRecipientTo(MessageTo);
mapi.AddAttachment(packageFile);
int sendResult = mapi.SendMailPopup(MessageSubject, MessageBody);
if (sendResult > 1)
{
string DesktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
File.Copy(packageFile, DesktopFolder + "\\bug_" + Path.GetFileNameWithoutExtension(packageFile)
+ "_" + DateTime.Now.ToString("yyyyMMddHHmm") + Path.GetExtension(packageFile), true);
MessageBox.Show("I'd copyed package.zip into desktop. Send it.");
}
}
catch (Exception ex)
{
MessageBox.Show("Can't process. Exception :" + ex.Message);
}
}


OnUnhandledException.

:
static void Main()
{
...
// UnhandledException
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(ProcessUnhandledException);
//
DebugTool.BindedFiles.Add(“logs.log”);
// MAPI
DebugTool.MessageTo = "...@gmail.com";
DebugTool.UnhandledMessageSubject = "Unhandled exception in your application";
DebugTool.BugMessageSubject = "Bug in application";
DebugTool.MessageBody = "<Please, leave here your comment>";
}

private static void ProcessUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
DebugTool.ProcessUnhandledException(e);
}


! , Ctrl-Shift-B .

Source: https://habr.com/ru/post/78863/


All Articles