Delphi深度探索-CodeSite应用指南
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Delphi深度探索-CodeSite应用指南相关的知识,希望对你有一定的参考价值。
参考技术ADelphi虽然为我们提供极其强大的调试功能 查找Bug仍然是一项艰巨的工作 通常我们写代码和调试代码的所消耗的时间是大致相同的 甚至有可能更多 为了减少无谓的时间和精力的浪费 有时我们还是需要专业调试工具的帮助来提高锁定Bug的效率 本文中我们将介绍著名的调试工具CodeSite Pro (它获得了 年度Delphi Informant读者选择的最佳调试工具奖的第二名) 它的官方网址是
CodeSite的主要功能是可以让开发者使用代码来发送运行时的详细信息到特殊的接收器 以便于进一步分析 更精确的说通过CodeSite实现的TCodeSite类 我们可以打包并发送运行时的信息给CodeSite Dispatcher(CodeSite的消息分发器) 它可以路由这些消息到一个或多个接收器来察看 缺省的信息接收器是CodeSite Viewer(消息察看器)
CodeSite的效率体现在它不同于简单的显示消息的对话框或设定断点来检查变量 它更类似于Delphi自带的事件日志功能(Event Log) 当然毫无疑问它要比Event Log强大的多 它的消息是可持续的 也就是可以保存的 便于回溯分析
在介绍CodeSite的具体使用前 我们先来看一下它的三个组成部分
CodeSite对象
正如前面提到的 从运行的应用程序中向外发送CodeSite消息是通过使用TCodeSite类(定义在CSIntf单元中)的一个实例来完成的 我们只要简单的调用TCodeSite类的方法就可以 把消息发送给CodeSite Dispatcher 比如 可以使用对象的SendMsg方法来发送一个简单的字符串消息 TCodeSite 对象实现了大量的方法来支持各种类型的信息发送而无须任何数据转换 比如对象的SendObject方法有两个参数 一个是消息字符串 一个是对对象实例的引用 这个方法会获取对象所有published的属性 然后把这些属性的信息打包进CodeSite的消息中
CodeSite Dispatcher
大多数情况下 CodeSite Dispatcher会安静的运行在系统的托盘区 它的唯一功能是路由从各个TCodeSite对象发来的CodeSite的消息到它们的目的地 缺省时 CodeSite消息都会发给CodeSite Viewer 我们甚至不需要启动CodeSite Dispatcher 因为它会被TCodeSite等对象自动启动
TCodeSite 类定义了一个DestinationDetails属性 它允许开发者设定发送的CodeSite消息是如何被CodeSite Dispatcher路由到不同目的地 比如日志文件 但通常没有必要修改这个属性
CodeSite Viewer
虽然CodeSite 支持发送消息到不同的目标 但决大多数情况下CodeSite Viewer是主要的发送目标 即使是发送到其他目标 比如日志文件或另外一台机器 CodeSite Viewer仍然是察看分析消息的主要工具
CodeSite Viewer由下面四个面板构成 消息列表 消息察看器 调用堆栈和Scratch面板 CodeSite Viewer的主要工作区是Message列表 它用来显示发送给Viewer的全部消息或是从日志文件中加载的消息
消息察看器用来察看同消息关联的额外信息 比如如果当前的消息是由SendObject方法发送的话 消息察看器就会显示对象全部的publised属性当前值
调用堆栈面板会根据c *** EnterMethod消息显示一个堆栈视图
Scratch面板则是用来显示非可持续的信息的 当我们想跟踪某些信息 但又不想在消息日志中记录它们的时候 比如当我们想察看象鼠标当前位置这类大量的并重复的消息时 Scratch面板是非常有用的 这时我们可以可以使用TCodeSite对象的WritePoint方法 并指定Line ID参数以便指定用来容纳鼠标信息的scratch面板行数
下面就让我们用一个简单的例子来演示一下如何从程序中发送消息给CodeSite Viewer
( )创建一个新的项目 然后切换组件面板到CodeSite页面(CodeSite安装后会在系统中安装两个组件TCSGlobalObject和TCSObject) 选择TCSGlobalObject组件然后放到窗体上 TCSGlobalObject组件提供了设计时对全局TCodeSite对象的交互(全局TCodeSite是在CSInft单元中被初始化的)
( )添加一个按钮 然后在它的OnClick事件中写下如下代码 //CodeSite就是全局的TCodeSite对象CodeSite SendMsg( CodeSite的第一条消息 );
( )编译并运行这个简单的程序 运行后点击按钮 CodeSite Dispatcher和CodeSite Viewer将会运行 同时在CodeSite Viewer的消息列表中将会看到程序发出的消息(注意 我们没有必要在程序运行前启动CodeSite Dispatcher和CodeSite Viewer 因为TCodeSite 对象在需要发送消息的时候会自动启动它们的) 运行结果如下图 所示
图 ( )接下来 停止程序 在OnClick事件处理过程中添加下面代码
CodeSite SendObject( Form Form )
( )重新编译运行程序 再点按钮一次 这回你会在CodeSite Viewer中看到两条消息 其中Form 对应的消息包括Form 的对象信息
( )为了看到Form 的相关联的对象信息 选择CodeSite Viewer的菜单命令View|Inspector会在消息列表右侧显示一个新的面板 Form 的published属性都被显示在其中 如下图 所示
图
( )再次停止程序 然后修改OnClick过程中代码如下 CodeSite EnterMethod( Button Click );CodeSite SendMsg( CodeSite的第一条消息 );CodeSite SendObject( Form Form );CodeSite ExitMethod( Button Click ); ( )这次我们再运行程序点击按钮后 就会看到 CodeSite的第一条消息 和 Form 的消息被缩进在 Button Click 消息之间 如下图 所示
图
通过添加EnterMethod和ExitMethod方法的调用 我们可以生成一个日志来记录方法何时被调用
看过例子之后 我们就会发现CodeSite的功能是非常强大的 我们只要简单的在程序中添加几条语句就可以生成非常详细的信息 并通过CodeSite Viewer以生动的图表表现出来 接下来 我们再来谈谈CodeSite的高级应用技术
发送消息到日志文件
每个程序或多或少都会有Bug 不在这时发生 也会在那时发生 短时间内不发生 很长时间就可能发作 有时反复出现 有时非常偶然的才能被发现 如果一个人告诉你他写的程序在任何时候都没有任何问题 他一定是在撒谎 正是由于Bug的偶然性和隐蔽性 就使得我们往往很难重复用户提交的Bug 这就给我们调试程序并找到问题的原因产生了极大的障碍 而CodeSite能够发送消息到日志文件的特性就使得用户报告Bug变得更容易 他们只要把运行时生成的信息文件提交就可以了 相应的我们调试程序的工作也会变得更轻松 我们可以使用CodeSite Viewer来直观的分析错误发生的原因和位置
要想改变消息发送的目标 我们可以通过设定TCodeSite 对象的DestinationDetails属性来实现 这项功能要求客户的机器上必须安装了CodeSite Dispatcher 它属于CodeSite中可自由分发的部分 下面的要讲具体过程仍然是基于前面讲过的例子
( )在窗体的OnCreate事件中添加下面代码
CodeSite DestinationDetails = File[Path=C FirstLog csl]
( )编译并余兴程序 这回我们在点击按钮后 消息就不再被发送给CodeSite Viewer而是发送到C盘的FirstLog csl文件中
( )使用CodeSite Viewer加载FirstLog csl文件 这回我们就象先前一样察看被保存的CodeSite消息了
( )如果我们想把消息同时发送到CodeSite Viewer和日志文件的话 只修改前面的代码为
CodeSite DestinationDetails = Viewer File[Path=C FirstLog csl]
发送用户定制的数据
虽然TCodeSite 类提供了大量的处理不同数据类型的方法 但有时我们可能会需要发送某种自定义格式的数据信息 为此 TCodeSite 类定义了SendCustomData 方法 它支持发送任意的数据类型 并会根据一个自定义的格式器来格式化数据以便CodeSite Viewer可以正确的显示数据
首先我们需要创建一个TCSFormatter 对象的子类 然后重载对象的FormatData InspectorType和TypeName方法 然后调用CodeSite对象管理器对象CSObjectManager的来注册新的TCSFormatter子类 此外 我们还需要调用RegisterCustomFormat方法来注册一个新的消息类型
下面是一个实际应用的例子 单元CSEmployee pas中实现了一个TCSEmployeeRecord记录类型的定制格式器 unit CSEmployee;interfaceusesWindows Graphics CSIntf;constc *** EmployeeSummary = c *** User + ;c *** EmployeeDetails = c *** User + ;
首先在Uses部分添加对CSIntf 单元的引用 第二步是为每一个格式器定义新的CodeSite消息类型常数 上面我们定义了两个常数 注意常数应该大于c *** User 但不能大过
typeTCSEmployee = recordLastName: string;FirstName: string;Address: string;City: string;State: string;ZipCode: string;PhoneNumber: string;HireDate: TDateTime;Salary: Currency;VacationDays: Integer;SickDays: Integer;Manager: Boolean;end; 上面的记录就是我们要发送的自定义的数据类型 TCSEmployeeSummaryFormatter = class( TCSFormatter )publicfunction InspectorType: TCSInspectorType; override;procedure FormatData( var Data ); override;function TypeName: string; override;end;TCSEmployeeDetailsFormatter = class( TCSFormatter )publicfunction InspectorType: TCSInspectorType; override;procedure FormatData( var Data ); override;function TypeName: string; override;end; 上面是两个定制的格式器类的定义 第一个格式器将把TCSEmployee 记录格式化为一个文本格式 第二个格式化器将把TCSEmployee 记录格式化为网格样式
实现一个自定义的格式化器的第一步是确定哪种类型的内置察看器将被用来察看格式化后的数据 这里使用的是字符串列表察看器 察看器类型将被FormatData方法所使用 procedure TCSEmployeeSummaryFormatter FormatData( var Data );varEmpRec: TCSEmployee;beginEmpRec := TCSEmployee( Data );AddLine( EmpRec FirstName + + EmpRec LastName );AddLine( EmpRec Address );AddLine( EmpRec City + + EmpRec State + + EmpRec ZipCode );AddLine( );AddLine( Phone: + EmpRec PhoneNumber );AddLine( Hire Date: + DateToStr( EmpRec HireDate ) );AddLine( Salary: + Format( %m [ EmpRec Salary ] ) );AddLine( );AddLine( Vacation Days: + IntToStr( EmpRec VacationDays ) );AddLine( Sick Days: + IntToStr( EmpRec SickDays ) );if EmpRec Manager thenAddLine( Manager: Yes )elseAddLine( Manager: No );end; FormatData 方法是核心部分 注意传递给FormatData方法的Data参数是一个无类型的可变参数 这就意味着这个参数可以是任何数据类型的 通过格式注册过程 我们可以确保强制类型映射为自定义的数据记录 而不会发生转换错误
转换数据类型后 我们就可以对数据进行格式化了 这里使用TCSFormatter 基类的 AddLine方法在字符串间添加分割线来进行格式化 function TCSEmployeeSummaryFormatter TypeName: string;beginResult := TCSEmployee ;end;
TypeName方法的重载是可任选的 但通常我们可以用它来返回显示在消息列表中的字符串 =========================================== TCSEmployeeDetailsFormatter Methods ===========================================function TCSEmployeeDetailsFormatter InspectorType: TCSInspectorType;beginResult := itStockGrid;end; 对于employeedetails格式器来说 命名网格察看器将被用来察看数据信息 procedure TCSEmployeeDetailsFormatter FormatData( var Data );varEmpRec: TCSEmployee;beginEmpRec := TCSEmployee( Data );AddNameValuePair( LastName EmpRec LastName );AddNameValuePair( FirstName EmpRec FirstName );AddNameValuePair( Address EmpRec Address );AddNameValuePair( City EmpRec City );AddNameValuePair( State EmpRec State );AddNameValuePair( ZipCode EmpRec ZipCode );AddNameValuePair( PhoneNumber EmpRec PhoneNumber );AddNameValuePair( HireDate EmpRec HireDate );AddNameValuePair( Salary Format( %m [ EmpRec Salary ] ) );AddNameValuePair( VacationDays EmpRec VacationDays );AddNameValuePair( SickDays EmpRec SickDays );AddNameValuePair( Manager EmpRec Manager );end; 这里为了在网格察看器中格式化数据 我们使用AddNameValuePair方法来实现 function TCSEmployeeDetailsFormatter TypeName: string;beginResult := TCSEmployee ;end; 下面两个过程是用来封装对SendCustomData方法的调用的 这里对全局的TCodeSite对象实例CodeSite进行了调用
======================= Support Methods =======================procedure CSSendEmployeeSummary( const Msg: string; EmpRec: TCSEmployee );beginCodeSite SendCustomData( c *** EmployeeSummary Msg EmpRec );end;procedure CSSendEmployeeDetails( const Msg: string; EmpRec: TCSEmployee );beginCodeSite SendCustomData( c *** EmployeeDetails Msg EmpRec );end; 最后 不要忘了调用CSObjectManager RegisterCustomFormatter方法把格式器注册到CodeSite对象管理器中
lishixinzhi/Article/program/Delphi/201311/24692
以上是关于Delphi深度探索-CodeSite应用指南的主要内容,如果未能解决你的问题,请参考以下文章
Delphi XE10 dxLayoutControl 控件应用指南
[原创]Delphi XE10 dxLayoutControl 控件应用指南