Как я получаю EXCEPTION_POINTERS
, то есть как:Как получить EXCEPTION_POINTERS во время исключения EExternal?
PEXCEPTION_RECORD
иPCONTEXT
данных во время EExternal
исключения?
фон
Когда Windows генерирует исключение, он пропускает PEXCEPTION_POINTERS
; указатель на информацию, за исключением:
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
Когда Delphi бросает мне EExternal
исключение, он содержит только половину этой информации, только PEXCEPTION_RECORD
:
EExternal = class(Exception)
public
ExceptionRecord: PExceptionRecord;
end;
Как, во время EExternal
исключения делать я получаю оба?
Пример
я пытаюсь написать Minidump с помощью MiniDumpWriteDump
функции из Delphi.
Функция имеет несколько дополнительных параметров:
function MiniDumpWriteDump(
hProcess: THandle; //A handle to the process for which the information is to be generated.
ProcessID: DWORD; //The identifier of the process for which the information is to be generated.
hFile: THandle; //A handle to the file in which the information is to be written.
DumpType: MINIDUMP_TYPE; //The type of information to be generated.
{in, optional}ExceptionParam: PMinidumpExceptionInformation; //A pointer to a MINIDUMP_EXCEPTION_INFORMATION structure describing the client exception that caused the minidump to be generated.
{in, optional}UserStreamParam: PMinidumpUserStreamInformation;
{in, optional}CallbackParam: PMinidumpCallbackInformation): Boolean;
На базовом уровне я могу опустить три дополнительных параметра:
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFileHandle,
nil, //PMinidumpExceptionInformation
nil,
nil);
и преуспевает. Недостатком является то, что в minidump отсутствует информация об исключении. Эта информация (необязательно) передается с помощью 4-я miniExceptionInfo параметра:
TMinidumpExceptionInformation = record
ThreadId: DWORD;
ExceptionPointers: PExceptionPointers;
ClientPointers: BOOL;
end;
PMinidumpExceptionInformation = ^TMinidumpExceptionInformation;
Это хорошо, за исключением того, что я нужен способ, чтобы получить в EXCEPTION_POINTERS
, которая поставляется Windows, когда происходит исключение.
TExceptionPointers
структура состоит из двух членов:
EXCEPTION_POINTERS = record
ExceptionRecord : PExceptionRecord;
ContextRecord : PContext;
end;
я знаю, что EExternal
исключение Delphi является основой всех "Windows" исключений, и содержит необходимое PExceptionRecord
:
EExternal = class(Exception)
public
ExceptionRecord: PExceptionRecord;
end;
Но он не содержит связанных ContextRecord
.
Не PEXCEPTION_RECORD
достаточно хорошо?
Если я пытаюсь передать EXCEPTION_POINTERS
в MiniDumpWriteDump
, оставив ContextRecord
ноль:
procedure TDataModule1.ApplicationEvents1Exception(Sender: TObject; E: Exception);
var
ei: TExceptionPointers;
begin
if (E is EExternal) then
begin
ei.ExceptionRecord := EExternal(E).ExceptionRecord;
ei.ContextRecord := nil;
GenerateDump(@ei);
end;
...
end;
function GenerateDump(exceptionInfo: PExceptionPointers): Boolean;
var
miniEI: TMinidumpExceptionInformation;
begin
...
miniEI.ThreadID := GetCurrentThreadID();
miniEI.ExceptionPointers := exceptionInfo;
miniEI.ClientPointers := True;
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFileHandle,
@miniEI, //PMinidumpExceptionInformation
nil,
nil);
end;
Тогда функция завершается с ошибкой 0x8007021B
только часть запроса ReadProcessMemory или WriteProcessMemory была завершена
Как насчет SetUnhandledExceptionFilter
?
Почему бы вам просто не использовать
SetUnhandledExceptionFilter
и получить указатель, в котором вы нуждаетесь?
SetUnhandledExceptionFilter(@DebugHelpExceptionFilter);
function DebugHelpExceptionFilter(const ExceptionInfo: TExceptionPointers): Longint; stdcall;
begin
GenerateDump(@ExceptionInfo);
Result := 1; //1 = EXCEPTION_EXECUTE_HANDLER
end;
Проблема с этим состоит в том, что нефильтрованный обработчик исключений только в кайф, если исключение не фильтруется. Потому что это Delphi, и потому, потому что я обрабатывать исключение:
procedure DataModule1.ApplicationEvents1Exception(Sender: TObject; E: Exception);
var
ei: TExceptionPointers;
begin
if (E is EExternal) then
begin
//If it's EXCEPTION_IN_PAGE_ERROR then we have to terminate *now*
if EExternal(E).ExceptionRecord.ExceptionCode = EXCEPTION_IN_PAGE_ERROR then
begin
ExitProcess(1);
Exit;
end;
//Write minidump
...
end;
{$IFDEF SaveExceptionsToDatabase}
SaveExceptionToDatabase(Sender, E);
{$ENDIF}
{$IFDEF ShowExceptionForm}
ShowExceptionForm(Sender, E);
{$ENDIF}
end;
Применение не, и я не хочу, чтобы это прекратить с ошибкой WER.
Как получить EXCEPTION_POINTERS
во время EExternal
?
Примечание: Вы можете игнорировать все: Фон на. Это излишне наполнитель, разработанный, чтобы заставить меня выглядеть умнее.
Преимущественное Heffernan комментарий элегантного: Вы должны прекратить использовать Delphi 5.
Bonus Чтение
- MSDN: Crash Dump Analysis (Windows) (подробный пример того, как назвать
MiniDumpWriteDump
) - CodeProject: Post-Mortem Debugging Your Application with Minidumps and Visual Studio .NET (Общие говорить о концепциях, достоинствах и способах создания и использования мини-насосов)
- Stackoverflow: How to create minidump for my process when it crashes? (первоначальное введение в мир мини-свалки)
- Stackoverflow: Can one prevent Microsoft Error Reporting for a single app? (настройка нефильтрованный обработчика в Delphi)
сообщение Преимущественное Heffernan комментарий: Я сомневаюсь, что это легче в более поздних версиях. И вам не нужно беспокоиться о x64. –
FWIW madExcept дает вам легкий доступ к контекстной записи –
madExcept получает контекст довольно гнусным способом. Он перехватывает ExceptObjProc. Который оказывается довольно сложным. Поскольку процесс подключения должен считывать некоторые регистры перед вызовом функции Pascal. Возможно, я мог бы решить, как это сделать, используя ME в качестве шаблона. Но это займет много времени. Лично я просто использую МЕНЯ. Как только у вас появится ME, я думаю, вам больше не нужны мини-кадры. Диагностика ME будет проще в использовании. –