2010-04-08 5 views
1

Im пытается сделать инструмент для моих конечных пользователей, который может создать MiniDump моего приложения, если он зависает (т. Е. Внешний к приложению). Я использую тот же код, что и внутренний MiniDumper, но с ручкой и processid приложения, но я продолжаю получать код ошибки 0xD0000024 при вызове MiniDumpWriteDump. Есть идеи?Создание MiniDump работающего процесса

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

этот код работает 100%, когда его внутренний к процессу (т.е. с функцией SetUnhandledExceptionFilter)

+0

Почему бы не просто указать их на ADPlus (часть бесплатных инструментов отладки для Windows)? См. Http://stackoverflow.com/questions/2591406/how-to-print-stack-trace-of-stackoverflowexception/2591466#2591466 – Richard

+0

@richard Любить 1 решение exe, но я проверю его – Lodle

+0

Не могли бы вы опубликовать код 'findProcess()'? – bk1e

ответ

1

Вы открытием процесса с необходимыми правами доступа? MiniDumpWriteDump() необходимо открыть дескриптор процесса с использованием PROCESS_QUERY_INFORMATION и PROCESS_VM_READ прав доступа. При использовании GetCurrentProcess() я думаю, что они предоставляются автоматически, но при использовании OpenProcess() для открытия другого процесса вам необходимо запросить эти права.

Для этого у вас есть может также имеет значение enable SeDebugPrivilege, что может вызвать проблемы у пользователей, чьи учетные записи не имеют этой привилегии. Но в документации, по-видимому, не ясно, необходимо ли SeDebugPrivilege для PROCESS_QUERY_INFORMATION и PROCESS_VM_READ прав (в отличие от всех прав доступа к процессу), особенно при открытии процесса, который работает как одна и та же учетная запись пользователя.

+0

Да, я был, кроме того, что я закрывал ручку, прежде чем возвращать ее. Другая вещь, которую я хочу знать, - это открыть дескриптор сервиса и взять свалку, поскольку я все время отказываюсь от разрешения. – Lodle

0

Я вижу, что вы явно меняете MyMiniDumpCallback как тип PMINIDUMP_CALLBACK_INFORMATION. Это выглядит подозрительно, как если бы у вас была ошибка компилятора, с которой вы сталкивались, потому что типы не совпадали. Это, и PMINIDUMP_CALLBACK_INFORMATION - это структура, а не указатель на функцию.

Прямой приведение указателя функции к PMINIDUMP_CALLBACK_INFORMATION может быть действительным, так как первым параметром этой структуры является функция обратного вызова. Но опять же, это выглядит действительно подозрительно. Возможно, вы неверно указали свою функцию обратного вызова (например, забыв модификатор CALLBACK/__ stdcall). Получите ваш код, чтобы скомпилировать, не вставляя эти формальные параметры сначала, тогда я буду более склонен вам помочь.

Кроме того, вы даже проверили, что ваша функция обратного вызова даже вызвана вообще?