我想使用MiniDumpWriteDump函数来创建一些自定义转储文件(主要是,我想导出包含线程调用堆栈的最少信息量的转储文件),但是我在定义需要的结构时遇到了困难作为参数传递给回调函数
[StructLayout(LayoutKind.Explicit)]
internal struct MINIDUMP_CALLBACK_OUTPUT
{
[FieldOffset(0)]
public ulong ModuleWriteFlags;
[FieldOffset(0)]
public ulong ThreadWriteFlags;
}
public struct MINIDUMP_CALLBACK_INFORMATION
{
public IntPtr CallbackRoutine;
public IntPtr CallbackParam;
}
public delegate bool MINIDUMP_CALLBACK_ROUTINE(
IntPtr CallBackParam,
MINIDUMP_CALLBACK_INPUT input,
MINIDUMP_CALLBACK_OUTPUT output);
[DllImport("dbghelp.dll")]
public static extern bool MiniDumpWriteDump(IntPtr hProcess, Int32 ProcessId, IntPtr hFile, int DumpType,
IntPtr ExceptionParam, IntPtr UserStreamParam, IntPtr CallStackParam);
电话看起来像这样:
MINIDUMP_CALLBACK_INFORMATION mci;
MINIDUMP_CALLBACK_ROUTINE r = new MINIDUMP_CALLBACK_ROUTINE(MyCallback);
GC.KeepAlive(r);
mci.CallbackRoutine = Marshal.GetFunctionPointerForDelegate(r);
mci.CallbackParam = IntPtr.Zero;
IntPtr structPointer = Marshal.AllocHGlobal(Marshal.SizeOf(mci));
Marshal.StructureToPtr(mci, structPointer, true);
MiniDumpWriteDump(process[0].Handle, process[0].Id,
fs.SafeFileHandle.DangerousGetHandle(),
(int)MINIDUMP_TYPE.MiniDumpNormal,
Marshal.GetExceptionPointers(),
IntPtr.Zero,
structPointer);
Marshal.FreeHGlobal(structPointer);
所以我的问题是如何定义MINIDUMP_CALLBACK_INPUT:
C中存在问题的结构的定义是:
typedef struct _MINIDUMP_CALLBACK_INPUT
{
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
union
{
MINIDUMP_THREAD_CALLBACK Thread;
MINIDUMP_THREAD_EX_CALLBACK ThreadEx;
MINIDUMP_MODULE_CALLBACK Module;
MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread;
MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule;
} u;
} MINIDUMP_CALLBACK_INPUT
typedef struct _MINIDUMP_MODULE_CALLBACK
{
PWCHAR FullPath;
ULONGLONG BaseOfImage;
ULONG SizeOfImage;
ULONG CheckSum;
ULONG TimeDateStamp;
VS_FIXEDFILEINFO VersionInfo;
PVOID CvRecord;
ULONG SizeOfCvRecord;
PVOID MiscRecord;
ULONG SizeOfMiscRecord;
} MINIDUMP_MODULE_CALLBACK
答案 0 :(得分:2)
这不是你问题的直接答案,而是一种解决方法......
你知道你所需要的ClrDump lib吗?几年前我用它来做一个项目,它对我来说很好。
回答作者评论 :
在网站上阅读:
ClrDump可以生成包含足够信息的小型小型转储,以恢复应用程序中所有线程的调用堆栈。
我将API包装在以下类中:
internal class ClrDump
{
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("clrdump.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern bool CreateDump(uint ProcessId, string FileName, MINIDUMP_TYPE DumpType, uint ExcThreadId, IntPtr ExtPtrs);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("clrdump.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern bool RegisterFilter(string FileName, MINIDUMP_TYPE DumpType);
[DllImport("clrdump.dll")]
public static extern FILTER_OPTIONS SetFilterOptions(FILTER_OPTIONS Options);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("clrdump.dll", SetLastError=true)]
public static extern bool UnregisterFilter();
[Flags]
public enum FILTER_OPTIONS
{
CLRDMP_OPT_CALLDEFAULTHANDLER = 1
}
[Flags]
public enum MINIDUMP_TYPE
{
MiniDumpFilterMemory = 8,
MiniDumpFilterModulePaths = 0x80,
MiniDumpNormal = 0,
MiniDumpScanMemory = 0x10,
MiniDumpWithCodeSegs = 0x2000,
MiniDumpWithDataSegs = 1,
MiniDumpWithFullMemory = 2,
MiniDumpWithFullMemoryInfo = 0x800,
MiniDumpWithHandleData = 4,
MiniDumpWithIndirectlyReferencedMemory = 0x40,
MiniDumpWithoutManagedState = 0x4000,
MiniDumpWithoutOptionalData = 0x400,
MiniDumpWithPrivateReadWriteMemory = 0x200,
MiniDumpWithProcessThreadData = 0x100,
MiniDumpWithThreadInfo = 0x1000,
MiniDumpWithUnloadedModules = 0x20
}
}
然后,在我的初始化代码中的某处,我调用了RegisterFilter方法,该方法在当前进程中为未处理的异常注册内部过滤器。如果进程因未处理的异常(可能是本机异常或托管异常)崩溃,则过滤器会捕获它并创建一个minidump(具有指定的文件名)。以下是此示例代码:
StringBuilder sb = new StringBuilder();
sb.Append(Path.GetFileNameWithoutExtension(Application.ExecutablePath));
sb.Append("_");
sb.Append(DateTime.Now.ToString("yyyyMMddHHmmssFF"));
sb.Append(".dmp");
string dmpFilePath = Path.Combine(Path.GetTempPath(), sb.ToString());
ClrDump.RegisterFilter(_dmpFilePath, ClrDump.MINIDUMP_TYPE.MiniDumpNormal);
您可以阅读this article以了解不同的MINIDUMP_TYPE选项,但我认为基本的(MiniDumpNormal)可以满足您的需求。
答案 1 :(得分:1)
使用此代码定义一个32位的union结构:
[StructLayout(LayoutKind.Explicit)]
internal struct MINIDUMP_CALLBACK_INPUT
{
[FieldOffset(0)]
UInt32 ProcessId;
[FieldOffset(4)]
IntPtr ProcessHandle;
[FieldOffset(8)]
UInt32 CallbackType;
[FieldOffset(12)]
MINIDUMP_THREAD_CALLBACK Thread;
[FieldOffset(12)]
MINIDUMP_THREAD_EX_CALLBACK ThreadEx;
[FieldOffset(12)]
MINIDUMP_MODULE_CALLBACK Module;
[FieldOffset(12)]
MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread;
[FieldOffset(12)]
MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule;
};
我认为在64位平台上,无论ULONG是64位还是32位,偏移量应分别为{0,8,16,24}或{0,4,12,16}。
修改强>
我认为您可以使用MarshalAsAttribute专门转换字段:
[StructLayout(LayoutKind.Sequential)]
struct VS_FIXEDFILEINFO
{
UInt32 dwSignature;
UInt32 dwStrucVersion;
UInt32 dwFileVersionMS;
UInt32 dwFileVersionLS;
UInt32 dwProductVersionMS;
UInt32 dwProductVersionLS;
UInt32 dwFileFlagsMask;
UInt32 dwFileFlags;
UInt32 dwFileOS;
UInt32 dwFileType;
UInt32 dwFileSubtype;
UInt32 dwFileDateMS;
UInt32 dwFileDateLS;
}
[StructLayout (LayoutKind.Sequential)]
struct MINIDUMP_MODULE_CALLBACK
{
[MarshalAs(UnmanagedType.LPWStr)]
String FullPath;
UInt64 BaseOfImage;
UInt32 SizeOfImage;
UInt32 CheckSum;
UInt32 TimeDateStamp;
VS_FIXEDFILEINFO VersionInfo;
IntPtr CvRecord;
UInt32 SizeOfCvRecord;
IntPtr MiscRecord;
UInt32 SizeOfMiscRecord;
}
答案 2 :(得分:0)
我认为正是工会给你带来了麻烦?
如果CallbackType == KernelMinidumpStatusCallback,则CALLBACK_INPUT结构定义为:
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
HRESULT Status;
如果CallbackType == ThreadCallback,则它是:
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
MINIDUMP_THREAD_CALLBACK Thread;
如果CallbackType == ThreadExCallback,则它是:
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
MINIDUMP_THREAD_EX_CALLBACK ThreadEx;
依此类推(这来自MSDN) - 看起来第4个成员可以是8种不同类型中的一种,具体取决于CallbackType等于什么。在内部,Windows将为所有这些结构使用相同的内存块(将较小的内存填充到最大的一个)。在C ++中,获取所需类型是一种简单的类型转换。
我不确定如何在C#中执行此操作。我在C ++中使用过MiniDumpWriteDump,但从未使用过回调函数。如果你可以确定CallbackType总是一个值,你可以只编写一个结构,但我不知道是否是这种情况。
抱歉,我无法提供更多信息,但这可能有助于描述问题。