Excptdlg.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:10k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {       Delphi VCL Extensions (RX)                      }
  4. {                                                       }
  5. {       Copyright (c) 1997, 1998 Master-Bank            }
  6. {                                                       }
  7. {*******************************************************}
  8. unit ExcptDlg;
  9. {$I RX.INC}
  10. interface
  11. uses
  12.   SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
  13.   StdCtrls, ExtCtrls, RXCtrls;
  14. type
  15.   TErrorEvent = procedure (Error: Exception; var Msg: string) of object;
  16.   TRxErrorDialog = class(TForm)
  17.     BasicPanel: TPanel;
  18.     ErrorText: TLabel;
  19.     IconPanel: TPanel;
  20.     IconImage: TImage;
  21.     TopPanel: TPanel;
  22.     RightPanel: TPanel;
  23.     DetailsPanel: TPanel;
  24.     MessageText: TMemo;
  25.     ErrorAddress: TEdit;
  26.     ErrorType: TEdit;
  27.     ButtonPanel: TPanel;
  28.     DetailsBtn: TButton;
  29.     OKBtn: TButton;
  30.     AddrLabel: TRxLabel;
  31.     TypeLabel: TRxLabel;
  32.     BottomPanel: TPanel;
  33.     procedure FormCreate(Sender: TObject);
  34.     procedure FormDestroy(Sender: TObject);
  35.     procedure FormShow(Sender: TObject);
  36.     procedure DetailsBtnClick(Sender: TObject);
  37.     procedure ErrorInfo(var LogicalAddress: Pointer; var ModuleName: string);
  38.     procedure FormKeyUp(Sender: TObject; var Key: Word;
  39.       Shift: TShiftState);
  40.   private
  41.     Details: Boolean;
  42.     DetailsHeight: Integer;
  43.     ExceptObj: Exception;
  44.     FPrevOnException: TExceptionEvent;
  45.     FOnErrorMsg: TErrorEvent;
  46. {$IFDEF WIN32}
  47.     FHelpFile: string;
  48. {$ENDIF}
  49.     procedure GetErrorMsg(var Msg: string);
  50.     procedure ShowError;
  51.     procedure SetShowDetails(Value: Boolean);
  52. {$IFDEF WIN32}
  53.     procedure WMHelp(var Message: TWMHelp); message WM_HELP;
  54. {$ENDIF}
  55.   public
  56.     procedure ShowException(Sender: TObject; E: Exception);
  57.     property OnErrorMsg: TErrorEvent read FOnErrorMsg write FOnErrorMsg;
  58.   end;
  59. const
  60.   ErrorDlgHelpCtx: THelpContext = 0;
  61. var
  62.   RxErrorDialog: TRxErrorDialog;
  63. procedure RxErrorIntercept;
  64. implementation
  65. uses
  66. {$IFDEF WIN32}
  67.   Windows, {$IFDEF RX_D3} ComObj, {$ELSE} OleAuto, {$ENDIF RX_D3}
  68. {$ELSE WIN32}
  69.   WinProcs, WinTypes, ToolHelp, Str16,
  70. {$ENDIF WIN32}
  71.   Consts, RxCConst, rxStrUtils, VCLUtils;
  72. {$R *.DFM}
  73. {$IFDEF RX_D3}
  74. resourcestring
  75. {$ELSE}
  76. const
  77. {$ENDIF}
  78.   SCodeError = '%s.'#13#10'Error Code: %.8x (%1:d).';
  79.   SModuleError = 'Exception in module %s.'#13#10'%s';
  80. const
  81.   CRLF = #13#10;
  82. procedure RxErrorIntercept;
  83. begin
  84.   if RxErrorDialog <> nil then RxErrorDialog.Free;
  85.   RxErrorDialog := TRxErrorDialog.Create(Application);
  86. end;
  87. { TRxErrorDialog }
  88. procedure TRxErrorDialog.ShowException(Sender: TObject; E: Exception);
  89. begin
  90.   Screen.Cursor := crDefault;
  91.   Application.NormalizeTopMosts;
  92.   try
  93.     if Assigned(FPrevOnException) then FPrevOnException(Sender, E)
  94.     else if (ExceptObj = nil) and not Application.Terminated then begin
  95.       ExceptObj := E;
  96.       try
  97.         ShowModal;
  98.       finally
  99.         ExceptObj := nil;
  100.       end;
  101.     end
  102.     else begin
  103.       if NewStyleControls then Application.ShowException(E)
  104.       else MessageDlg(E.Message + '.', mtError, [mbOk], 0);
  105.     end;
  106.   except
  107.     { ignore any exceptions }
  108.   end;
  109.   Application.RestoreTopMosts;
  110. end;
  111. {$IFDEF WIN32}
  112. function ConvertAddr(Address: Pointer): Pointer; assembler;
  113. asm
  114.         TEST    EAX,EAX
  115.         JE      @@1
  116.         SUB     EAX, $1000
  117. @@1:
  118. end;
  119. procedure TRxErrorDialog.ErrorInfo(var LogicalAddress: Pointer;
  120.   var ModuleName: string);
  121. var
  122.   Info: TMemoryBasicInformation;
  123.   Temp, ModName: array[0..MAX_PATH] of Char;
  124. begin
  125.   VirtualQuery(ExceptAddr, Info, SizeOf(Info));
  126.   if (Info.State <> MEM_COMMIT) or
  127.     (GetModuleFilename(THandle(Info.AllocationBase), Temp,
  128.     SizeOf(Temp)) = 0) then
  129.   begin
  130.     GetModuleFileName(HInstance, Temp, SizeOf(Temp));
  131.     LogicalAddress := ConvertAddr(LogicalAddress);
  132.   end
  133.   else Integer(LogicalAddress) := Integer(LogicalAddress) -
  134.     Integer(Info.AllocationBase);
  135. {$IFDEF RX_D3}
  136.   StrLCopy(ModName, AnsiStrRScan(Temp, '') + 1, SizeOf(ModName) - 1);
  137. {$ELSE}
  138.   StrLCopy(ModName, StrRScan(Temp, '') + 1, SizeOf(ModName) - 1);
  139. {$ENDIF}
  140.   ModuleName := StrPas(ModName);
  141. end;
  142. {$ELSE}
  143. function ConvertAddr(Address: Pointer): Pointer; assembler;
  144. asm
  145.         MOV     AX,Address.Word[0]
  146.         MOV     DX,Address.Word[2]
  147.         MOV     CX,DX
  148.         OR      CX,AX
  149.         JE      @@1
  150.         CMP     DX,0FFFFH
  151.         JE      @@1
  152.         MOV     ES,DX
  153.         MOV     DX,ES:Word[0]
  154. @@1:
  155. end;
  156. procedure TRxErrorDialog.ErrorInfo(var LogicalAddress: Pointer;
  157.   var ModuleName: string);
  158. var
  159.   GlobalEntry: TGlobalEntry;
  160.   hMod: THandle;
  161.   ModName: array[0..15] of Char;
  162.   Buffer: array[0..255] of Char;
  163. begin
  164.   GlobalEntry.dwSize := SizeOf(GlobalEntry);
  165.   if GlobalEntryHandle(@GlobalEntry, THandle(PtrRec(LogicalAddress).Seg)) then
  166.     with GlobalEntry do begin
  167.       hMod := hOwner;
  168.       if wType in [GT_CODE, GT_DATA, GT_DGROUP] then
  169.         PtrRec(LogicalAddress).Seg := wData;
  170.     end
  171.     else LogicalAddress := ConvertAddr(LogicalAddress);
  172.   GetModuleFileName(hMod, Buffer, SizeOf(Buffer));
  173.   StrLCopy(ModName, StrRScan(Buffer, '') + 1, SizeOf(ModName) - 1);
  174.   ModuleName := StrPas(ModName);
  175. end;
  176. {$ENDIF}
  177. procedure TRxErrorDialog.ShowError;
  178. var
  179.   S, ModuleName: string;
  180.   P: Pointer;
  181. begin
  182.   P := ExceptAddr;
  183.   ModuleName := '';
  184.   ErrorInfo(P, ModuleName);
  185.   AddrLabel.Enabled := (P <> nil);
  186.   ErrorAddress.Text := Format('%p', [ExceptAddr]);
  187.   ErrorType.Text := ExceptObj.ClassName;
  188.   TypeLabel.Enabled := ErrorType.Text <> '';
  189.   S := Trim(ExceptObj.Message);
  190.   if Pos(CRLF, S) = 0 then
  191.     S := ReplaceStr(S, #10, CRLF);
  192.   if ExceptObj is EInOutError then
  193.     S := Format(SCodeError, [S, EInOutError(ExceptObj).ErrorCode])
  194. {$IFDEF WIN32}
  195.   else if ExceptObj is EOleException then begin
  196.     with EOleException(ExceptObj) do
  197.       if (Source <> '') and (AnsiCompareText(S, Trim(Source)) <> 0) then
  198.         S := S + CRLF + Trim(Source);
  199.     S := Format(SCodeError, [S, EOleException(ExceptObj).ErrorCode])
  200.   end
  201.   else if ExceptObj is EOleSysError then
  202.     S := Format(SCodeError, [S, EOleSysError(ExceptObj).ErrorCode])
  203.   else if ExceptObj is EExternalException then
  204.     S := Format(SCodeError, [S,
  205.       EExternalException(ExceptObj).ExceptionRecord^.ExceptionCode])
  206. {$ENDIF}
  207. {$IFDEF RX_D3}
  208.   else if ExceptObj is EWin32Error then
  209.     S := Format(SCodeError, [S, EWin32Error(ExceptObj).ErrorCode])
  210. {$ENDIF}
  211.   else S := S + '.';
  212.   MessageText.Text := Format(SModuleError, [ModuleName, S]);
  213. end;
  214. procedure TRxErrorDialog.SetShowDetails(Value: Boolean);
  215. begin
  216.   DisableAlign;
  217.   try
  218.     if Value then begin
  219.       DetailsPanel.Height := DetailsHeight;
  220.       ClientHeight := DetailsPanel.Height + BasicPanel.Height;
  221.       DetailsBtn.Caption := '<< &' + LoadStr(SDetails);
  222.       ShowError;
  223.     end
  224.     else begin
  225.       ClientHeight := BasicPanel.Height;
  226.       DetailsPanel.Height := 0;
  227.       DetailsBtn.Caption := '&' + LoadStr(SDetails) + ' >>';
  228.     end;
  229.     DetailsPanel.Enabled := Value;
  230.     Details := Value;
  231.   finally
  232.     EnableAlign;
  233.   end;
  234. end;
  235. procedure TRxErrorDialog.GetErrorMsg(var Msg: string);
  236. var
  237.   I: Integer;
  238. begin
  239.   I := Pos(CRLF, Msg);
  240.   if I > 0 then System.Delete(Msg, I, MaxInt);
  241.   if Assigned(FOnErrorMsg) then
  242.     try
  243.       FOnErrorMsg(ExceptObj, Msg);
  244.     except
  245.     end;
  246. end;
  247. {$IFDEF WIN32}
  248. procedure TRxErrorDialog.WMHelp(var Message: TWMHelp);
  249. var
  250.   AppHelpFile: string;
  251. begin
  252.   AppHelpFile := Application.HelpFile;
  253.   try
  254.     if FHelpFile <> '' then
  255.       Application.HelpFile := FHelpFile;
  256.     inherited;
  257.   finally
  258.     Application.HelpFile := AppHelpFile;
  259.   end;
  260. end;
  261. {$ENDIF}
  262. procedure TRxErrorDialog.FormCreate(Sender: TObject);
  263. begin
  264. {$IFDEF WIN32}
  265.   BorderIcons := [biSystemMenu, biHelp];
  266. {$ELSE}
  267.   BorderIcons := [];
  268. {$ENDIF}
  269.   DetailsHeight := DetailsPanel.Height;
  270.   Icon.Handle := LoadIcon(0, IDI_HAND);
  271.   IconImage.Picture.Icon := Icon;
  272.   { Load string resources }
  273.   Caption := ResStr(SMsgDlgError);
  274.   OKBtn.Caption := ResStr(SOKButton);
  275.   { Set exception handler }
  276.   FPrevOnException := Application.OnException;
  277.   Application.OnException := ShowException;
  278. end;
  279. procedure TRxErrorDialog.FormDestroy(Sender: TObject);
  280. begin
  281.   Application.OnException := FPrevOnException;
  282. end;
  283. procedure TRxErrorDialog.FormShow(Sender: TObject);
  284. var
  285.   S: string;
  286. {$IFDEF WIN32}
  287.   ExStyle: Longint;
  288. {$ENDIF}
  289. begin
  290.   if ExceptObj.HelpContext <> 0 then
  291.     HelpContext := ExceptObj.HelpContext
  292.   else HelpContext := ErrorDlgHelpCtx;
  293. {$IFDEF WIN32}
  294.   if ExceptObj is EOleException then
  295.     FHelpFile := EOleException(ExceptObj).HelpFile
  296.   else FHelpFile := '';
  297.   ExStyle := GetWindowLong(Handle, GWL_EXSTYLE);
  298.   if (HelpContext <> 0) then
  299.     ExStyle := ExStyle or WS_EX_CONTEXTHELP
  300.   else
  301.     ExStyle := ExStyle and not WS_EX_CONTEXTHELP;
  302.   SetWindowLong(Handle, GWL_EXSTYLE, ExStyle);
  303. {$ENDIF}
  304.   S := Trim(ExceptObj.Message) + '.';
  305.   GetErrorMsg(S);
  306.   ErrorText.Caption := S;
  307.   SetShowDetails(False);
  308.   DetailsBtn.Enabled := True;
  309. end;
  310. procedure TRxErrorDialog.DetailsBtnClick(Sender: TObject);
  311. begin
  312.   SetShowDetails(not Details);
  313. end;
  314. procedure TRxErrorDialog.FormKeyUp(Sender: TObject; var Key: Word;
  315.   Shift: TShiftState);
  316. {$IFDEF WIN32}
  317. var
  318.   Info: THelpInfo;
  319. {$ENDIF}
  320. begin
  321.   if (Key = VK_F1) and (HelpContext <> 0) then begin
  322. {$IFDEF WIN32}
  323.     with Info do begin
  324.       cbSize := SizeOf(THelpInfo);
  325.       iContextType := HELPINFO_WINDOW;
  326.       iCtrlId := 0;
  327.       hItemHandle := Handle;
  328.       dwContextId := HelpContext;
  329.       GetCursorPos(MousePos);
  330.     end;
  331.     Perform(WM_HELP, 0, Longint(@Info));
  332. {$ELSE}
  333.     Application.HelpContext(HelpContext);
  334. {$ENDIF}
  335.   end;
  336. end;
  337. initialization
  338.   RxErrorDialog := nil;
  339. end.