Delphi:Exception输出堆栈信息
起源:
用习惯了c#之Exception的StackTrace,在程序出异常crash时候能够以其定位出问题的模块及行号,用回Delphi 2009,发现没有这东西。
显然,在编译环境日新月异的今天,是不科学的。分析Delphi的Exception,发现些线索:StackTrace。
应该有戏!
继续下去,验证输出这个StackTrace,它是空的,里面没有预想要的内容。再深究去,发现并没想象那么容易,它扯到不少蛋。
1、Exception类
Delphi 2009中,StackTrace是如此定义的,与它一起的还有几个var:
Exception = class(TObject)
private
...
protected
...
public
...
property StackTrace: string read GetStackTrace;
property StackInfo: Pointer read FStackInfo;
{$IFDEF MSWINDOWS}
class var
// Hook this function to return an opaque data structure that contains stack information
// for the given exception information record. This function will be called when the
// exception is about to be raised or if this is an external exception such as an
// Access Violation, called soon after the object is created.
GetExceptionStackInfoProc: function (P: PExceptionRecord): Pointer;
// This function is called to return a string representation of the above opaque
// data structure
GetStackInfoStringProc: function (Info: Pointer): string;
// This function is called when the destructor is called to clean up any data associated
// with the given opaque data structure.
CleanUpStackInfoProc: procedure (Info: Pointer);
// Use this function to raise an exception instance from within an exception handler and
// you want to "acquire" the active exception and chain it to the new exception and preserve
// the context. This will cause the FInnerException field to get set with the exception
// in currently in play.
// You should only call this procedure from within an except block where the this new
// exception is expected to be handled elsewhere.
class procedure RaiseOuterException(E: Exception); static;
// Provide another method that does the same thing as RaiseOuterException, but uses the
// C++ vernacular of "throw"
class procedure ThrowOuterException(E: Exception); static;
{$ENDIF}
end;
明明白白的说,我东西给你了,你要用,自己想办法。你编译环境都不能实现,让我想什么办法?去它主页上看看:

蛋疼之极,欲用StackTrace,它居然要求我们用第三方的解决方案。如此不负责任!
好吧,上JEDI。
2、JclDebug
StackOverflow是个技术的绝佳去处,曾在其上受益不少,再去找找,果然有所得。
有个家伙封装了实现方法,借鉴下来,代码如下:
unit StackTrace; interface uses
SysUtils, Classes, JclDebug; implementation function GetExceptionStackInfoProc(P: PExceptionRecord): Pointer;
var
LLines: TStringList;
LText: String;
LResult: PChar;
begin
LLines := TStringList.Create;
try
JclLastExceptStackListToStrings(LLines, True, True, True, True);
LText := LLines.Text;
LResult := StrAlloc(Length(LText));
StrCopy(LResult, PChar(LText));
Result := LResult;
finally
LLines.Free;
end;
end; function GetStackInfoStringProc(Info: Pointer): string;
begin
Result := string(PChar(Info));
end; procedure CleanUpStackInfoProc(Info: Pointer);
begin
StrDispose(PChar(Info));
end; initialization
// Start the Jcl exception tracking and register our Exception
// stack trace provider.
if JclStartExceptionTracking then
begin
Exception.GetExceptionStackInfoProc := GetExceptionStackInfoProc;
Exception.GetStackInfoStringProc := GetStackInfoStringProc;
Exception.CleanUpStackInfoProc := CleanUpStackInfoProc;
end; finalization
// Stop Jcl exception tracking and unregister our provider.
if JclExceptionTrackingActive then
begin
Exception.GetExceptionStackInfoProc := nil;
Exception.GetStackInfoStringProc := nil;
Exception.CleanUpStackInfoProc := nil;
JclStopExceptionTracking;
end; end.
很是优美。但单步去跟,发现GetExceptionStackInfoProc中,其返回值为空。
作者也发现了,所幸另个人解决这个问题,替换其函数如下:
function GetExceptionStackInfoProc(P: PExceptionRecord): Pointer;
var
LLines: TStringList;
LText: String;
LResult: PChar;
jcl_sil: TJclStackInfoList;
begin
LLines := TStringList.Create;
try
jcl_sil := TJclStackInfoList.Create(True, , p.ExceptAddr, False, nil, nil);
try
jcl_sil.AddToStrings(LLines, true, true, true, true);
finally
FreeAndNil(jcl_sil);
end;
LText := LLines.Text;
LResult := StrAlloc(Length(LText));
StrCopy(LResult, PChar(LText));
Result := LResult;
finally
LLines.Free;
end;
end;
验证OK,解决问题!


这样,可以挂接Application.OnException,自个处理程序的Crash异常了。
注意事项:用JEDI求堆栈信息,须设置Delphi工程属性之Linking->Map file值为Detailed,它是基于解析map文件生成数据:

参考资料:
System.SysUtils.Exception.StackTrace
Delphi - Trying to get StackTrace for an exception
Delphi:Exception输出堆栈信息的更多相关文章
- Slf4j 打日志的问题 Exception 没有堆栈信息
Slf4j 打日志的问题 Exception 没有堆栈信息 发现线上环境有的Exception堆栈信息没打出来,只有异常信息没有堆栈信息,难以定位 一般情况下日志这么打 log.info(" ...
- C++ crash 堆栈信息获取(三篇文章)
最近在做程序异常时堆栈信息获取相关工作,上一篇文章成功的在程序creash时写下了dump文件,而有些情况写dump文件是 不可以的,比如在jni开发时,C++只做底层处理,而整个项目是android ...
- 在Linux与Windows上获取当前堆栈信息
在编写稳定可靠的软件服务时经常用到输出堆栈信息,以便用户/开发者获取准确的运行信息.常用在日志输出,错误报告,异常检测. 在Linux有比较简便的函数获取堆栈信息: #include <stdi ...
- C++ crash 堆栈信息获取
最近在做程序异常时堆栈信息获取相关工作,上一篇文章成功的在程序creash时写下了dump文件,而有些情况写dump文件是 不可以的,比如在jni开发时,C++只做底层处理,而整个项目是android ...
- C++ crash 堆栈信息获取(三篇)
最近在做程序异常时堆栈信息获取相关工作,上一篇文章成功的在程序creash时写下了dump文件,而有些情况写dump文件是 不可以的,比如在jni开发时,C++只做底层处理,而整个项目是android ...
- 使用log4j的时候如何输出printStackTrace()的堆栈信息
使用log4j的时候如何输出printStackTrace()的堆栈信息 研究了一下发现很简单,如下: log.error(e.getMessage(),e); 输出信息如下: 2009-05-11 ...
- Delphi中使用Dos窗口输出调试信息
在项目文件 *.DPR (Project->View Source) 里加上{$APPTYPE CONSOLE} 然后,在需要输出处加上 Writeln(‘your debug messa ...
- Delphi之Exception获得错误信息(简单好理解)
Delphi之Exception获得错误信息 相关资料: http://www.cnblogs.com/hackpig/archive/2010/02/15/1668547.html 实例代码: 1 ...
- Delphi RAD Berlin OutputDebugString 输出调试信息
Delphi RAD Berlin Event Log.OutputDebugString 输出调试信息,仅在win VCL下可以用.OutputDebugString(PChar('hellowor ...
随机推荐
- jinjia
https://www.cnblogs.com/dachenzi/p/8242713.html
- vue 源码阅读记录
0.webpack默认引入的是vue.runtime.common.js,并不是vue.js,功能有略微差别,不影响使用 1.阅读由ts编译后的js: 入口>构造函数 >定义各类方法 &g ...
- javascript:图片转base64
第一种: <!DOCTYPE html><html> <head> <meta charset="utf-8"> <meta ...
- tips___代码规范
函数变量尽可能置于最小作用域内,并在变量声明时进行初始化 变量声明的位置最好离第一次使用的位置越近越好:应使用初始化的方式代替声明再赋值. int x=0; rather than int x; x ...
- Raft算法和Gossip协议
简单介绍下集群数据同步,集群监控用到的两种常见算法. Raft算法 raft 集群中的每个节点都可以根据集群运行的情况在三种状态间切换:follower, candidate 与 leader.lea ...
- Oracle相关文章
1.oracle 11g常用命令 2.Oracle的在windows下的安装及使用 3.Oracle scott账户被锁定,scott默认密码,sys,system默认密码 4.NaviCat Pri ...
- ReactiveX 学习笔记(8)错误处理和 To 操作符
Error Handling Operators Operators to Convert Observables 本文的主题为对 Observable 进行错误处理的操作符以及转换 Observab ...
- 前后台联调,突然所有的接口请求状态为200,但response什么都没有只有一句灰色的英文
问题解决了,图就下次遇到截图补上: 解决问题的方法,是让后台查看数据库是否锁库,或者更改什么配置文件例如.xml文件,还有就是ip错误:
- asp.net 服务器 上传文件到 FTP服务器
private string ftpServerIP = "服务器ip";//服务器ip private string ftpUserID = "ftp的用户名" ...
- C# 汉字转拼音(全拼)
C# 汉字转拼音(全拼) 很多时候我们需要把汉字转换成拼音,比如姓名.城市名等.网上搜索了一把,把汉字转成拼音的代码很多,但大多都只是把汉字转成了拼音的首字母,比如把“深圳”转成了“sz”.那 ...