c++ - 创建正在运行的进程的 MiniDump

标签 c++ winapi minidump

我正在尝试为我的最终用户制作一个工具,如果它挂起(即在应用程序外部),它可以创建我的应用程序的 MiniDump。我使用与内部 MiniDumper 相同的代码,但使用应用程序的句柄和进程 ID,但在调用 MiniDumpWriteDump 时我不断收到错误代码 0xD0000024。有什么想法吗?

void produceDump( const char* exe )
{
    DWORD processId = 0;
    HANDLE process = findProcess(exe, processId);

    if (!process || processId == 0)
    {
        printf("Unable to find exe %s to produce dump.\n", exe);
        return;
    }

    LONG retval = EXCEPTION_CONTINUE_SEARCH;
    HWND hParent = NULL;                        // find a better value for your app

    // firstly see if dbghelp.dll is around and has the function we need
    // look next to the EXE first, as the one in System32 might be old 
    // (e.g. Windows 2000)
    HMODULE hDll = NULL;
    char szDbgHelpPath[_MAX_PATH];

    if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
    {
        char *pSlash = _tcsrchr( szDbgHelpPath, '\\' );
        if (pSlash)
        {
            _tcscpy( pSlash+1, "DBGHELP.DLL" );
            hDll = ::LoadLibrary( szDbgHelpPath );
        }
    }

    if (hDll==NULL)
    {
        // load any version we can
        hDll = ::LoadLibrary( "DBGHELP.DLL" );
    }

    LPCTSTR szResult = NULL;

    int err = 0;

    if (hDll)
    {
        MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
        if (pDump)
        {
            char szDumpPath[_MAX_PATH];
            char szScratch [_MAX_PATH];

            time_t rawtime;
            struct tm * timeinfo;

            time ( &rawtime );
            timeinfo = localtime ( &rawtime );

            char comAppPath[MAX_PATH];
            SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA , NULL, SHGFP_TYPE_CURRENT, comAppPath );


            //COMMONAPP_PATH
            _snprintf(szDumpPath, _MAX_PATH, "%s\\DN", comAppPath);
            CreateDirectory(szDumpPath, NULL);

            _snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D", comAppPath);
            CreateDirectory(szDumpPath, NULL);

            _snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D\\dumps", comAppPath);
            CreateDirectory(szDumpPath, NULL);

            char fileName[_MAX_PATH];
            _snprintf(fileName, _MAX_PATH, "%s_Dump_%04d%02d%02d_%02d%02d%02d.dmp", exe, timeinfo->tm_year+1900, timeinfo->tm_mon, timeinfo->tm_mday,  timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec );
            _snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D\\dumps\\%s", comAppPath, fileName);

            // create the file
            HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
            if (hFile!=INVALID_HANDLE_VALUE)
            {
                MINIDUMP_CALLBACK_INFORMATION mci; 

                mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback; 
                mci.CallbackParam       = 0; 

                MINIDUMP_TYPE mdt       = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | 
                                                          MiniDumpWithDataSegs | 
                                                          MiniDumpWithHandleData |
                                                          //MiniDumpWithFullMemoryInfo | 
                                                          //MiniDumpWithThreadInfo | 
                                                          MiniDumpWithProcessThreadData |
                                                          MiniDumpWithUnloadedModules ); 

                // write the dump
                BOOL bOK = pDump( process, processId, hFile, mdt, NULL, NULL, &mci );
                DWORD lastErr = GetLastError();

                if (bOK)
                {
                    printf("Crash dump saved to: %s\n", szDumpPath);
                    return;
                }
                else
                {
                    _snprintf( szScratch, _MAX_PATH, "Failed to save dump file to '%s' (error %u)", szDumpPath, lastErr);
                    szResult = szScratch;
                    err = ERR_CANTSAVEFILE;
                }
                ::CloseHandle(hFile);
            }
            else
            {
                _snprintf( szScratch, _MAX_PATH, "Failed to create dump file '%s' (error %u)", szDumpPath, GetLastError());
                szResult = szScratch;
                err = ERR_CANTMAKEFILE;
            }
        }
        else
        {
            szResult = "DBGHELP.DLL too old";
            err = ERR_DBGHELP_TOOLD;
        }
    }
    else
    {
        szResult = "DBGHELP.DLL not found";
        err = ERR_DBGHELP_NOTFOUND;
    }

    printf("Could not produce a crash dump of %s.\n\n[error: %u %s].\n", exe, err, szResult);
    return;
}

此代码在进程内部(即使用 SetUnhandledExceptionFilter)时 100% 有效

最佳答案

您是否以必要的访问权限打开进程? MiniDumpWriteDump()需要使用 PROCESS_QUERY_INFORMATIONPROCESS_VM_READ 访问权限打开进程句柄。使用 GetCurrentProcess() 时,我认为这些是自动授予的,但使用 OpenProcess() 时要打开另一个进程,您必须请求这些权限。

为此,您可能还必须 enable SeDebugPrivilege ,这会给帐户没有该权限的用户带来问题。但是文档似乎并不清楚 SeDebugPrivilege 是否对 PROCESS_QUERY_INFORMATIONPROCESS_VM_READ 权限(相对于所有进程访问权限)是必要的),特别是在打开以同一用户帐户运行的进程时。

关于c++ - 创建正在运行的进程的 MiniDump,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2598615/

相关文章:

c++ - Nginx + fastcgi 多线程

c - 如何从 pid 中杀死(和关闭)标签?

c++ - 获取 SFML 窗口的 HWND 和 HInstance?

python - 用 Python 编写 Windows 迷你转储

windows - 打印 windows coredump 的堆栈跟踪,无需以交互方式进入 windbg/visual studio

c# - 使用 MiniDump (DbgHelp.h) 获取句柄数据

c++ - 我如何找出下一个 C++ 的特定建议/论文的状态?

c++ - 当按下鼠标左键时,在 SFML 2.0 中也按下了

C++11 "overloaded lambda"带有可变参数模板和变量捕获

c++ - IOCP 和 ReadFileEx 用法