1

我试图为我的最终用户制作一个工具,如果它挂起(即在应用程序外部),它可以创建我的应用程序的 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% 工作

4

2 回答 2

2

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

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

于 2010-04-09T05:03:18.783 回答
0

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

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

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

于 2010-04-09T05:22:38.580 回答