我想使用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发布于 2009-09-01 12:10:14
这不是对你问题的直接回答,而是一种变通办法...
你知道做你需要的事情的ClrDump库吗?我在几年前的一个项目中使用过它,它对我来说运行得很好。
对作者评论的回答
在网站上阅读:
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方法,该方法为当前进程中未处理的异常注册一个内部筛选器。如果进程因未处理的异常(可以是本机异常或托管异常)而崩溃,则筛选器会捕获该异常并创建一个小型转储(具有指定的文件名)。下面是一个示例代码:
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)可以满足您的需求。
发布于 2009-09-02 06:25:38
使用此代码定义32位联合的结构:
[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;
}发布于 2009-09-01 18:18:00
我想是工会给你惹麻烦了吧?
如果为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 --看起来第四个成员可以是8个不同类型中的一个,这取决于CallbackType等于什么。在内部,Windows将对所有这些结构使用相同的内存块(将较小的结构填充到最大的结构)。在C++中,它是获取所需类型的简单类型转换。
我不确定如何在C#中做到这一点。我在C++中使用过MiniDumpWriteDump,但从未使用过回调函数。如果您可以确保CallbackType始终是一个值,那么您可以只编写一个结构,但我不知道情况是否如此。
很抱歉,我无法提供更多信息,但这可能有助于描述问题。
https://stackoverflow.com/questions/1361787
复制相似问题