5

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
4

3 に答える 3

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 メソッドを呼び出しました。処理されない例外 (ネイティブまたはマネージ例外の可能性があります) でプロセスがクラッシュした場合、フィルターはそれをキャッチし、(指定されたファイル名で) ミニダンプを作成します。これのサンプルコードは次のとおりです。

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);

この記事を読んで、さまざまな MINIDUMP_TYPE オプションを理解できますが、基本的なもの (MiniDumpNormal) がニーズに合うと思います。

于 2009-09-01T12:10:13.547 に答える
1

次のコードを使用して、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-02T06:25:37.933 に答える
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からのものです) - CallbackType が何に等しいかに応じて、4 番目のメンバーは 8 つの異なるタイプのいずれかになるようです。内部的には、Windows はこれらすべての構造に対して同じメモリ チャンクを使用します (小さいものを最大のサイズにパディングします)。C++ では、必要な型を取得するのは簡単な型キャストです。

C# でこれを行う方法がわかりません。C++ で MiniDumpWriteDump を使用したことがありますが、コールバック関数を使用したことはありません。CallbackType が常に 1 つの値であると確信できる場合は、その 1 つの構造体をコーディングするだけで済みますが、これが当てはまるかどうかはわかりません。

申し訳ありませんが、これ以上の情報を提供することはできませんが、これが問題の説明に役立つかもしれません。

于 2009-09-01T18:18:00.027 に答える