📄 exceptdlg.pas
字号:
begin
Screen.Cursor := crHourGlass;
DetailsMemo.Lines.BeginUpdate;
try
CreateDetailInfo;
ReportToLog;
DetailsMemo.SelStart := 0;
SendMessage(DetailsMemo.Handle, EM_SCROLLCARET, 0, 0);
AfterCreateDetails;
finally
DetailsMemo.Lines.EndUpdate;
OkBtn.Enabled := True;
DetailsBtn.Enabled := True;
OkBtn.SetFocus;
Screen.Cursor := crDefault;
end;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.CreateReport(const SystemInfo: TExcDialogSystemInfos);
const
MMXText: array[Boolean] of PChar = ('', 'MMX');
FDIVText: array[Boolean] of PChar = (' [FDIV Bug]', '');
var
SL: TStringList;
I: Integer;
ModuleName: TFileName;
CpuInfo: TCpuInfo;
C: TWinControl;
NtHeaders: PImageNtHeaders;
ModuleBase: Cardinal;
ImageBaseStr: string;
StackList: TJclStackInfoList;
begin
SL := TStringList.Create;
try
// Stack list
if siStackList in SystemInfo then
begin
StackList := JclLastExceptStackList;
if Assigned(StackList) then
begin
DetailsMemo.Lines.Add(Format(RsStackList, [DateTimeToStr(StackList.TimeStamp)]));
StackList.AddToStrings(DetailsMemo.Lines, False, True, True);
NextDetailBlock;
end;
end;
// System and OS information
if siOsInfo in SystemInfo then
begin
DetailsMemo.Lines.Add(Format(RsOSVersion, [GetWindowsVersionString, NtProductTypeString,
Win32MajorVersion, Win32MinorVersion, Win32BuildNumber, Win32CSDVersion]));
GetCpuInfo(CpuInfo);
with CpuInfo do
DetailsMemo.Lines.Add(Format(RsProcessor, [Manufacturer, CpuName,
RoundFrequency(FrequencyInfo.NormFreq),
MMXText[MMX], FDIVText[IsFDIVOK]]));
DetailsMemo.Lines.Add(Format(RsScreenRes, [Screen.Width, Screen.Height, GetBPP]));
NextDetailBlock;
end;
// Modules list
if (siModuleList in SystemInfo) and LoadedModulesList(SL, GetCurrentProcessId) then
begin
DetailsMemo.Lines.Add(RsModulesList);
{$IFDEF DELPHI4}
StringListCustomSort(SL, SortModulesListByAddressCompare);
{$ELSE DELPHI4}
SL.CustomSort(SortModulesListByAddressCompare);
{$ENDIF DELPHI4}
for I := 0 to SL.Count - 1 do
begin
ModuleName := SL[I];
ModuleBase := Cardinal(SL.Objects[I]);
DetailsMemo.Lines.Add(Format('[%.8x] %s', [ModuleBase, ModuleName]));
NtHeaders := PeMapImgNtHeaders(Pointer(ModuleBase));
if (NtHeaders <> nil) and (NtHeaders^.OptionalHeader.ImageBase <> ModuleBase) then
ImageBaseStr := Format('<%.8x> ', [NtHeaders^.OptionalHeader.ImageBase])
else
ImageBaseStr := StrRepeat(' ', 11);
if VersionResourceAvailable(ModuleName) then
with TJclFileVersionInfo.Create(ModuleName) do
try
DetailsMemo.Lines.Add(ImageBaseStr + BinFileVersion + ' - ' + FileVersion);
if FileDescription <> '' then
DetailsMemo.Lines.Add(StrRepeat(' ', 11) + FileDescription);
finally
Free;
end
else
DetailsMemo.Lines.Add(ImageBaseStr + RsMissingVersionInfo);
end;
NextDetailBlock;
end;
// Active controls
if (siActiveControls in SystemInfo) and (FLastActiveControl <> nil) then
begin
DetailsMemo.Lines.Add(RsActiveControl);
C := FLastActiveControl;
while C <> nil do
begin
DetailsMemo.Lines.Add(Format('%s "%s"', [C.ClassName, C.Name]));
C := C.Parent;
end;
NextDetailBlock;
end;
finally
SL.Free;
end;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.DetailsBtnClick(Sender: TObject);
begin
DetailsVisible := not DetailsVisible;
end;
//--------------------------------------------------------------------------------------------------
class procedure TExceptionDialog.ExceptionHandler(Sender: TObject; E: Exception);
begin
if ExceptionShowing then
Application.ShowException(E)
else
begin
ExceptionShowing := True;
try
ShowException(E, nil);
finally
ExceptionShowing := False;
end;
end;
end;
//--------------------------------------------------------------------------------------------------
class procedure TExceptionDialog.ExceptionThreadHandler(Thread: TJclDebugThread);
begin
if ExceptionShowing then
Application.ShowException(Thread.SyncException)
else
begin
ExceptionShowing := True;
try
ShowException(Thread.SyncException, Thread);
finally
ExceptionShowing := False;
end;
end;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.FormCreate(Sender: TObject);
begin
FSimpleLog := TSimpleExceptionLog.Create;
FFullHeight := ClientHeight;
DetailsVisible := False;
Caption := Format(RsAppError, [Application.Title]);
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.FormDestroy(Sender: TObject);
begin
FreeAndNil(FSimpleLog);
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if (Key = Ord('C')) and (ssCtrl in Shift) then
begin
CopyReportToClipboard;
MessageBeep(MB_OK);
end;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.FormPaint(Sender: TObject);
begin
DrawIcon(Canvas.Handle, TextLabel.Left - GetSystemMetrics(SM_CXICON) - 15,
TextLabel.Top, LoadIcon(0, IDI_ERROR));
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.FormResize(Sender: TObject);
begin
UpdateTextLabelScrollbars;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.FormShow(Sender: TObject);
begin
BeforeCreateDetails;
MessageBeep(MB_ICONERROR);
if FIsMainThead and (GetWindowThreadProcessId(Handle, nil) = MainThreadID) then
PostMessage(Handle, UM_CREATEDETAILS, 0, 0)
else
CreateDetails;
end;
//--------------------------------------------------------------------------------------------------
function TExceptionDialog.GetReportAsText: string;
begin
Result := StrEnsureSuffix(AnsiCrLf, TextLabel.Text) + AnsiCrLf + DetailsMemo.Text;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.NextDetailBlock;
begin
DetailsMemo.Lines.Add(StrRepeat(ReportNewBlockDelimiterChar, ReportMaxColumns));
end;
//--------------------------------------------------------------------------------------------------
function TExceptionDialog.ReportMaxColumns: Integer;
begin
Result := 100;
end;
//--------------------------------------------------------------------------------------------------
function TExceptionDialog.ReportNewBlockDelimiterChar: Char;
begin
Result := '-';
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.ReportToLog;
begin
if Tag and ReportToLogEnabled <> 0 then
begin
FSimpleLog.WriteStamp(ReportMaxColumns);
try
FSimpleLog.Write(ReportAsText);
finally
FSimpleLog.CloseLog;
end;
end;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.SetDetailsVisible(const Value: Boolean);
var
DetailsCaption: string;
begin
FDetailsVisible := Value;
DetailsCaption := Trim(StrRemoveChars(DetailsBtn.Caption, ['<', '>']));
if Value then
begin
Constraints.MinHeight := FNonDetailsHeight + 100;
Constraints.MaxHeight := Screen.Height;
DetailsCaption := '<< ' + DetailsCaption;
ClientHeight := FFullHeight;
DetailsMemo.Height := FFullHeight - DetailsMemo.Top - 3;
end
else
begin
FFullHeight := ClientHeight;
DetailsCaption := DetailsCaption + ' >>';
if FNonDetailsHeight = 0 then
begin
ClientHeight := Bevel1.Top;
FNonDetailsHeight := Height;
end
else
Height := FNonDetailsHeight;
Constraints.MinHeight := FNonDetailsHeight;
Constraints.MaxHeight := FNonDetailsHeight
end;
DetailsBtn.Caption := DetailsCaption;
DetailsMemo.Enabled := Value;
end;
//--------------------------------------------------------------------------------------------------
class procedure TExceptionDialog.ShowException(E: Exception; Thread: TJclDebugThread);
begin
if ExceptionDialog = nil then
ExceptionDialog := ExceptionDialogClass.Create(Application);
try
with ExceptionDialog do
begin
FIsMainThead := (GetCurrentThreadId = MainThreadID);
FLastActiveControl := Screen.ActiveControl;
TextLabel.Text := AdjustLineBreaks(StrEnsureSuffix('.', E.Message));
UpdateTextLabelScrollbars;
DetailsMemo.Lines.Add(Format(RsExceptionClass, [E.ClassName]));
if Thread = nil then
DetailsMemo.Lines.Add(Format(RsExceptionAddr, [ExceptAddr]))
else
DetailsMemo.Lines.Add(Format(RsThread, [Thread.ThreadInfo]));
NextDetailBlock;
ShowModal;
end;
finally
FreeAndNil(ExceptionDialog);
end;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.UMCreateDetails(var Message: TMessage);
begin
Update;
CreateDetails;
end;
//--------------------------------------------------------------------------------------------------
procedure TExceptionDialog.UpdateTextLabelScrollbars;
begin
if Tag and DisableTextScrollbar = 0 then
begin
Canvas.Font := TextLabel.Font;
if TextLabel.Lines.Count * Canvas.TextHeight('Wg') > TextLabel.ClientHeight then
TextLabel.ScrollBars := ssVertical
else
TextLabel.ScrollBars := ssNone;
end;
end;
//==================================================================================================
// Exception handler initialization code
//==================================================================================================
procedure InitializeHandler;
begin
JclStackTrackingOptions := JclStackTrackingOptions + [stRawMode];
{$IFNDEF HOOK_DLL_EXCEPTIONS}
JclStackTrackingOptions := JclStackTrackingOptions + [stStaticModuleList];
{$ENDIF HOOK_DLL_EXCEPTIONS}
JclDebugThreadList.OnSyncException := TExceptionDialog.ExceptionThreadHandler;
JclStartExceptionTracking;
{$IFDEF HOOK_DLL_EXCEPTIONS}
if HookTApplicationHandleException then
JclTrackExceptionsFromLibraries;
{$ENDIF HOOK_DLL_EXCEPTIONS}
Application.OnException := TExceptionDialog.ExceptionHandler;
end;
//--------------------------------------------------------------------------------------------------
procedure UnInitializeHandler;
begin
Application.OnException := nil;
JclDebugThreadList.OnSyncException := nil;
JclUnhookExceptions;
JclStopExceptionTracking;
end;
//--------------------------------------------------------------------------------------------------
initialization
InitializeHandler;
finalization
UnInitializeHandler;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -