首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用回调调用MiniDumpWriteDump

使用回调调用MiniDumpWriteDump
EN

Stack Overflow用户
提问于 2009-09-01 10:54:21
回答 3查看 4.4K关注 0票数 5

我想使用MiniDumpWriteDump函数创建一些自定义转储文件(主要是,我想导出一个包含线程调用堆栈最少信息的转储文件),但是定义需要作为参数传递给回调函数的结构有困难

代码语言:javascript
复制
[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);

调用看起来是这样的:

代码语言:javascript
复制
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中提出问题的结构的定义是:

代码语言:javascript
复制
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
EN

回答 3

Stack Overflow用户

发布于 2009-09-01 12:10:14

这不是对你问题的直接回答,而是一种变通办法...

你知道做你需要的事情的ClrDump库吗?我在几年前的一个项目中使用过它,它对我来说运行得很好。

对作者评论的回答

在网站上阅读:

ClrDump可以生成小型转储,其中包含足够的信息来恢复应用程序中所有线程的调用堆栈。

我将API封装在以下类中:

代码语言:javascript
复制
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方法,该方法为当前进程中未处理的异常注册一个内部筛选器。如果进程因未处理的异常(可以是本机异常或托管异常)而崩溃,则筛选器会捕获该异常并创建一个小型转储(具有指定的文件名)。下面是一个示例代码:

代码语言:javascript
复制
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)可以满足您的需求。

票数 2
EN

Stack Overflow用户

发布于 2009-09-02 06:25:38

使用此代码定义32位联合的结构:

代码语言:javascript
复制
[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专门转换字段:

代码语言:javascript
复制
  [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;
  }
票数 1
EN

Stack Overflow用户

发布于 2009-09-01 18:18:00

我想是工会给你惹麻烦了吧?

如果为CallbackType==KernelMinidumpStatusCallback,则CALLBACK_INPUT结构定义为:

代码语言:javascript
复制
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
HRESULT Status;

如果为CallbackType==ThreadCallback,则为:

代码语言:javascript
复制
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
MINIDUMP_THREAD_CALLBACK Thread;

如果为CallbackType==ThreadExCallback,则为:

代码语言:javascript
复制
ULONG ProcessId;
HANDLE ProcessHandle;
ULONG CallbackType;
MINIDUMP_THREAD_EX_CALLBACK ThreadEx;

依此类推(这来自MSDN --看起来第四个成员可以是8个不同类型中的一个,这取决于CallbackType等于什么。在内部,Windows将对所有这些结构使用相同的内存块(将较小的结构填充到最大的结构)。在C++中,它是获取所需类型的简单类型转换。

我不确定如何在C#中做到这一点。我在C++中使用过MiniDumpWriteDump,但从未使用过回调函数。如果您可以确保CallbackType始终是一个值,那么您可以只编写一个结构,但我不知道情况是否如此。

很抱歉,我无法提供更多信息,但这可能有助于描述问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1361787

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档