创建正在运行的进程的MiniDump

时间:2010-04-08 08:57:31

标签: c++ winapi minidump

我试图为我的最终用户制作一个工具,如果它挂起(即应用程序外部),可以创建我的应用程序的MiniDump。我使用与内部MiniDumper相同的代码,但使用应用程序的句柄和processid,但我在调用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%工作

2 个答案:

答案 0 :(得分:2)

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

为此,您可能也必须enable SeDebugPrivilege,这会导致帐户没有该权限的用户出现问题。但是文档似乎并不清楚SeDebugPrivilege是否需要PROCESS_QUERY_INFORMATIONPROCESS_VM_READ权利(而不是所有进程访问权限),特别是在打开一个进程时作为相同的用户帐户运行。

答案 1 :(得分:0)

我看到你明确地将MyMiniDumpCallback转换为PMINIDUMP_CALLBACK_INFORMATION类型。这看起来很可疑,就好像你有一个编译器错误,因为类型不匹配你正在解决。那,PMINIDUMP_CALLBACK_INFORMATION是一个结构,而不是一个函数指针。

指向PMINIDUMP_CALLBACK_INFORMATION的函数指针的直接转换可能是有效的,因为该结构的第一个参数是回调函数。但同样,它看起来真的很可疑。也许你错误地声明了你的回调函数(比如忘记了CALLBACK / __ stdcall修饰符)。让代码编译而不先抛出那些正式的参数,然后我会更倾向于帮助你。

另外,你甚至检查过你的回调函数是否被调用了?