Here is that helper class (Updated 19 Sept 2011 to fix some bugs).
using System.Runtime.InteropServices;
using System;
using System.IO;
using System.Diagnostics;
using System.Threading;
public static class DbgHelp
{
[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct MINIDUMP_EXCEPTION_INFORMATION
{
public uint ThreadId;
public IntPtr ExceptionPointers;
[MarshalAs(UnmanagedType.Bool)]
public bool ClientPointers;
}
[DllImport("Dbghelp.dll")]
static extern bool MiniDumpWriteDump(
IntPtr hProcess,
uint ProcessId,
IntPtr hFile,
[MarshalAs(UnmanagedType.I4)] MiniDumpType DumpType,
IntPtr ExceptionParam, // Ptr to MINIDUMP_EXCEPTION_INFORMATION
IntPtr UserStreamParam,
IntPtr CallbackParam);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
enum MiniDumpType : int
{
MiniDumpNormal = 0x00000000,
MiniDumpWithDataSegs = 0x00000001,
MiniDumpWithFullMemory = 0x00000002, // required for .NET apps
MiniDumpWithHandleData = 0x00000004,
MiniDumpFilterMemory = 0x00000008,
MiniDumpScanMemory = 0x00000010,
MiniDumpWithUnloadedModules = 0x00000020,
MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
MiniDumpFilterModulePaths = 0x00000080,
MiniDumpWithProcessThreadData = 0x00000100,
MiniDumpWithPrivateReadWriteMemory = 0x00000200,
MiniDumpWithoutOptionalData = 0x00000400,
MiniDumpWithFullMemoryInfo = 0x00000800,
MiniDumpWithThreadInfo = 0x00001000,
MiniDumpWithCodeSegs = 0x00002000,
MiniDumpWithoutAuxiliaryState = 0x00004000,
MiniDumpWithFullAuxiliaryState = 0x00008000,
MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
MiniDumpIgnoreInaccessibleMemory = 0x00020000,
MiniDumpWithTokenInformation = 0x00040000
};
public static void WriteExceptionDump(string filePath)
{
var proc = Process.GetCurrentProcess();
int win32Error;
if(!TryCreateDump(filePath, proc.Handle, (uint)proc.Id, GetCurrentThreadId(), Marshal.GetExceptionPointers(), out win32Error))
throw new Exception("Couldn't create dump file! Error: 0x" + win32Error.ToString("X8"));
}
public static bool TryCreateDump(string dumpFilePath, IntPtr processHandle, uint processId, uint threadId, IntPtr exceptionPointers, out int win32Error)
{
bool success = false;
int lastError = 0;
// Dump on a seperate thread - IsBackground=false is important to stop the process exiting while we write the dump
// also works around an issue of VS not being able to walk the callstack of the crashing thread
var thread = new Thread(new ThreadStart(() => {
// In-process dumps must ClientPointers = false
// If ClientPointers is false, or if there are no ExceptionPointers we must pass IntPtr.Zero as ExceptionInfo
var exceptionParam = IntPtr.Zero;
if (processId != Process.GetCurrentProcess().Id && exceptionPointers != IntPtr.Zero)
{
var ei = new MINIDUMP_EXCEPTION_INFORMATION {
ClientPointers = true, // in-process dump. True if we're dumping external processes
ExceptionPointers = exceptionPointers, // may be IntPtr.zero for CLR exceptions
ThreadId = threadId,
};
exceptionParam = Marshal.AllocHGlobal(Marshal.SizeOf(ei));
Marshal.PtrToStructure(exceptionParam, ei);
}
using (var outputFile = new FileStream(dumpFilePath, FileMode.Create))
{
success = MiniDumpWriteDump(
processHandle,
processId,
outputFile.SafeFileHandle.DangerousGetHandle(),
MiniDumpType.MiniDumpWithFullMemory,
exceptionParam,
IntPtr.Zero,
IntPtr.Zero);
}
if (!success)
lastError = Marshal.GetLastWin32Error();
if (exceptionParam != IntPtr.Zero)
Marshal.FreeHGlobal(exceptionParam);
})) { IsBackground = false, Name = "MiniDump thread" };
thread.Start();
thread.Join();
win32Error = lastError;
return success;
}
}
No comments:
Post a Comment