煮茶入门讲座如何调试你的程序

主题:煮茶入门讲座如何调试你的程序
主讲:D10.天地弦
Demo Tools:DebugTest   和EurekaLog v4.57 Enterprise Delphi.BCB  (入门群里有共享)
D10.天地弦 14:48:59
我在这个社区里经常看到一些问题
adoMain.Sql.Text :='select * from Orders'+
+' and OrderId = ' + edOrderId.Text
+' and CustomerID = ' + edCustomerId.Text
 
D10.天地弦 14:49:05
为什么不行啊,这样的问题
D10.天地弦 14:49:24
这种问题讲完以后如果还有人问大伙都不要理了...
 
D10.天地弦 14:53:02
只是一个比喻...
 
D10.天地弦 14:52:43
大家打开DebugTest.bpg
 D10.天地弦 14:53:53
打开没有?
 
D10.天地弦 14:52:29
现在开始第一个段落
风魂 14:54:00
开了
赤无极 14:54:04
打开听
D10.天地弦 14:54:09
大家配置一下ADOConnection...
D10.天地弦 14:54:19
都会配置吧
D10.天地弦 14:54:32
是连到Northxxx数据库的...
D10.天地弦 14:55:17
配置好了支一声...
B13.往生无语 14:55:30
好了
B6.银狼 14:55:35
好了
 
 D10.天地弦 14:55:47
可以运行程序了..
 
在CustomerId输入值 'VINET'
D10.天地弦 14:57:43
Start Query..
D10.天地弦 14:58:55
Start Query了没有?
B6.银狼 14:58:58
输入VINET,出错
D10.天地弦 14:59:03
y
B6.银狼 14:59:06
不输入,OK
D10.天地弦 14:59:10
en
D10.天地弦 14:59:16
大家先做到这一部
 D10.天地弦 15:01:09
好了,现在我们来开始调试
D10.天地弦 15:01:46
即然是StartQuery出来的错误,那我们在BtnStartQuery.Click事件中开始分析
D10.天地弦 15:02:01
回到Delphi界面
D10.天地弦 15:02:15
打开主窗体...
D10.天地弦 15:02:31
看到procedure TFMainForm.btnStartQueryClick(Sender: TObject);
const
  MAINSQL = 'select * from Orders';
var
  lcondi: string;
  lsql: string;
begin
  lcondi := InnerGetQueryCondition;
  lsql := MAINSQL;
  if lcondi <> '' then lsql := lsql + ' Where ' + lcondi;
  adoMain.Close;
  adoMain.CommandText := lsql;
  adoMain.Open;
end;
 
D10.天地弦 15:02:35
这个函数...
D10.天地弦 15:03:32
在函数体的第一个设置一个断点开始查找为什么会出错...
 
尖椒牛柳 15:03:33
看懂了
D10.天地弦 15:04:12
这堂课主要是教大家如果调试,以后可以自己搞定自己的问题...
D10.天地弦 15:04:22
 
 
 
 
D10.天地弦 15:04:36
设置断点....按F9运行程序....
 D10.天地弦 15:05:55
在CustomerId输入值按StartQuery...
D10.天地弦 15:06:21
程序会返回到Delphi设置了断点的地方
 
 
{
D10.天地弦 15:06:49
这里提一下F7,F8,F9这三个功能
D10.天地弦 15:07:42
F7是进入函数体....
F8是运行这一行,不进入函数体
F9从当前行开始运行
}
 
 D10.天地弦 15:08:00
现在按F8
D10.天地弦 15:08:06
执行当前行....
D10.天地弦 15:08:43
按F8直到弹出错误提示...
D10.天地弦 15:09:37
大伙可以找到是哪一行执行的时候出现了错误?
 
 
 
D10.天地弦 15:10:47
打开一个数据集的时候出错,结合弹出的提示可以看出来是CommandText设定出错了...
D10.天地弦 15:10:49
对不...
F6.Jeanvi 15:11:14
嗯.
D10.天地弦 15:11:20
这样的错误是最好找的....
D10.天地弦 15:11:31
好,我们再来一次
小小 15:11:51
好 
小小 15:12:02
继续啊 
D10.天地弦 15:12:10
在adoMain.Open这一行停下来....
 
 
 D10.天地弦 15:14:52
我们现在在Open之前看看到底Sql语句是什么东东
 
B6.银狼 15:16:12
怎么出来的啊
D10.天地弦 15:16:13
可以看到这个adoMain.CommandText的值(Sql)是什么了...
D10.天地弦 15:16:31
在adoMain.Open这一行停下来
F6.Jeanvi 15:16:35
ctr+f7
D10.天地弦 15:16:45
adoMain.CommandText选定这个
D10.天地弦 15:16:51
按Ctrl + F7
D10.天地弦 15:17:16
select * from Orders Where  CustomerID = VINET
看到这个值后,觉得这个值有错吗?
 
D10.天地弦 15:17:50
如果觉得没有错马上打开
SQL 查询分析器将刚刚看到的值Sql粘贴到查询分析器里
B6.银狼 15:18:50
收到
D10.天地弦 15:19:09
再执行...
 
D10.天地弦 15:19:29
在这里可以发现是不是Sql语句的问题....
D10.天地弦 15:19:46
多数是Sql语句不正确引起的...
F2.歪歪宝 15:19:49
D10.天地弦 15:20:29
可以发现CustomerId是个字符字段。应该
select * from Orders Where  CustomerID = 'VINET'
D10.天地弦 15:20:32
这样....
D10.天地弦 15:20:47
这样我们就可以找到错误所在
D10.天地弦 15:21:36
现在大家都知道修改程序找到这个错误....
D10.天地弦 15:21:43
可不可以....
D10.天地弦 15:22:14
可以的吱一声....
尖椒牛柳 15:22:16
可以
总结:
D10.天地弦 15:25:15
上面这一小节,要学到怎么样在程序出错的时候
1.大概找到程序出错的位置
2.根据错误提示,初步判断出错的东东
3.查看对象变量的值.
 
D10.天地弦 15:25:47
还有要懂得在调试程序中活用F7,F8,F9
{暂时告一段落}
 
 
 
 
B6.银狼 15:28:51
继续DLL吧
B13.往生无语 15:28:58
是的。。生成的文件有当前的cpu信息。信息。还有出错的语句
 B13.往生无语 15:29:19
但是出现内存错误的时候,比如内存泄漏就不行。 
 D10.天地弦 15:29:33
继续运行
看第二个错误...
mmoSql里的的sql语句有错么?
 
D10.天地弦 15:32:31
为什么会出错...
尖椒牛柳 15:32:39
 
D10.天地弦 15:32:46
如果删除掉注释看看...
尖椒牛柳 15:33:13
删除注释是可以的
 
B6.银狼 15:33:42
是啊
D10.天地弦 15:33:46
可以确定是注释惹的祸
D10.天地弦 15:33:54
难道不用能注释?
D10.天地弦 15:34:00
想想
D10.天地弦 15:34:18
/*-------------------------------
-------------------------------*/
SELECT *
       FROM Orders
       ORDER BY OrderId
D10.天地弦 15:34:38
发现变成这样也不会出错
D10.天地弦 15:34:50
原来注释是可以用的...
 D10.天地弦 15:36:59
有些问题要靠自己去想象,,,
D10.天地弦 15:37:10
去不断去测试
  
 
 
 
D10.天地弦 15:38:33
在设计时将mmoSql的值copy到adoMain.CommandText里面
 D10.天地弦 15:37:41
---------------------------
Debugger Exception Notification
---------------------------
Project DebugTest.exe raised exception class EOleException with message '不正常地定义参数对象。提供了不一致或不完整的信息。'. Process stopped. Use Step or Run to continue.
---------------------------
OK   Help  
---------------------------
 
D10.天地弦 15:38:07
可以从错误信息上看出是参数惹的祸
 
 D10.天地弦 15:39:47
再设定adoMain的Acitve为true
JERRY 15:40:07
那是什么东东
D10.天地弦 15:40:17
发现出现了同样的错误对不以
尖椒牛柳 15:40:41
超过字符长度了
 
D10.天地弦 15:40:46
看看他的Parmaters
D10.天地弦 15:40:17
发现出现了同样的错误对不以
尖椒牛柳 15:40:41
超过字符长度了
 
D10.天地弦 15:40:46
看看他的Parmaters
D10.天地弦 15:40:47
 
D10.天地弦 15:40:50
不是
尖椒牛柳 15:41:01
哦有“:
D10.天地弦 15:41:16
发现他的Parameters里无故出错了几个参数...
D10.天地弦 15:41:17
是不是
 
尖椒牛柳 15:41:35
有“:”的话,Delphi会认为是参数的
 
D10.天地弦 15:41:43
对...
D10.天地弦 15:41:50
这也是Delphi的不对了...
尖椒牛柳 15:41:58
上次这个问题我也调试了半天
 
D10.天地弦 15:42:09
把注释里的东东都解析出参数来搞...
 
 
再看下个列子
 
D10.天地弦 15:46:45
大伙把
FMainForm里的
  / ebugIntf := CreateDebugService;
D10.天地弦 15:46:58
constructor TFMainForm.Create(AOwner: TComponent);
begin
  inherited;
  // FebugIntf := CreateDebugService;
end;
这个注释搞掉
 
再运行程序...
D10.天地弦 15:48:43
还是运行主程序...
D10.天地弦 15:49:01
 
D10.天地弦 15:49:10
是这一行惹的祸...
D10.天地弦 15:49:20
function CreateDebugService(): IDebugIntf;
D10.天地弦 15:49:27
看看这个函数,,有没有什么问题...
D10.天地弦 15:50:20
这样的错误,不注意还很难找...
 D10.天地弦 15:54:01
function CreateDebugService: IDebugIntf; stdcall;
begin
  result := TDebugService.Create();
end;
function CreateDebugService(): IDebugIntf;
D10.天地弦 15:54:08
看到没有
飘尘 15:54:10
function CreateDebugService(): IDebugIntf;stdcall
D10.天地弦 15:54:24
让大家找只是告诉大伙不要粗心...
D10.天地弦 15:54:35
DLL内的原型是有stdcall的
B6.银狼 15:54:48
没看到啊
D10.天地弦 15:54:57
在function CreateDebugService(): IDebugIntf;加上
D10.天地弦 15:55:00
就可以运行了
D10.天地弦 15:55:15
  DebugIntf;
function CreateDebugService(): IDebugIntf;stdcall;
implementation
function CreateDebugService; external 'dkTools.dll' name 'CreateDebugService';
end.
 D10.天地弦 15:55:22
这样再运行就可以了...
B6.银狼 15:55:53
unit DebugIntf;
interface
type
  IDebugIntf = interface
    function RandomFormNo: WideString; safecall;
    function GetGuid: WideString; safecall;
  end;
implementation
end.
B6.银狼 15:55:55
F6.Jeanvi 15:55:55
 
赤无极 15:55:59
找到啦
D10.天地弦 15:56:04
DLL要注意函数的导出原形...
Locet 15:56:13
到哪里了?刚才在忙
赤无极 15:56:17
library dkTools;
{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }
uses
  ExceptionLog,
  SysUtils,
  Classes,
  DebugIntfImp in 'DebugIntfImp.pas',
  DebugIntf in '..\DebugIntf.pas';
{$R *.res}
function CreateDebugService: IDebugIntf; stdcall;
begin
  result := TDebugService.Create();
end;
exports
  CreateDebugService;
end.
 
D10.天地弦 15:56:36
 
D10.天地弦 15:56:53
好了马上要结束这场入门课了...
D10.天地弦 15:57:13
要调式DLL内的程序,
Locet 15:57:14
.........
F6.Jeanvi 15:57:15
D10, 用DLL的子块可否有办法直接共享一个数据连接? 如果不用包的话.
D10.天地弦 15:57:21
先切换到DLL工程
飘尘 15:57:42
DLL内部的的调试。哈哈
D10.天地弦 15:57:50
F6,用包来得更爽,讲完再讨论这个...
D10.天地弦 15:58:08
切换到DLL工程
飘尘 15:58:09
你还没有讲了
D10.天地弦 15:58:23
设置一下
D10.天地弦 15:58:35
设置一下Run Paramters就可以了
 
D10.天地弦 15:59:17
设定好了就可以像单个程序一样,在DLL设置断点,调试程序了
F2.歪歪宝 15:59:46
这不是必须用那个工具了
D10.天地弦 15:59:54
 
D10.天地弦 15:59:58
不是...
D10.天地弦 16:00:04
这个是自带的功能
D10.天地弦 16:00:16
那个只是我推荐的一个调试工具
D10.天地弦 16:00:21
帮了我不少忙了....
D10.天地弦 16:00:41
设置好没有?
D10.天地弦 16:00:53
设置好了就按F9
赤无极 16:01:03
好啦
D10.天地弦 16:01:05
还有,刚刚调用方式那里改了没有
 
D10.天地弦 16:01:12
Stdcall加上没有
D10.天地弦 16:01:18
加上也要编译一下主程序...
D10.天地弦 16:02:00
 
运行程序发现程序断了...
D10.天地弦 16:02:06
这一句是
B6.银狼 16:02:19
看不到图片
D10.天地弦 16:02:23
刚刚在主程序的constructor函数内调用的...
D10.天地弦 16:02:35
constructor TFMainForm.Create(AOwner: TComponent);
begin
  inherited;
  FDebugIntf := CreateDebugService;
end;
 
D10.天地弦 16:02:43
创建DLL内的一个服务...
D10.天地弦 16:03:06
因为这里执行这句,所以会调用到DLL里的那个函数了...
小小 16:03:39
嗯,Continue...
D10.天地弦 16:03:40
来到这里没有?
D10.天地弦 16:03:50
按F7进去吧
D10.天地弦 16:03:59
constructor TDebugService.Create;
begin
  inherited Create();
  FDate := FormatDateTime('YYYYMMDD', Now());
end;
D10.天地弦 16:04:03
进入了这里...
D10.天地弦 16:04:18
创建这个对象...
D10.天地弦 16:04:34
如果刚刚那里按F8就不会来到这里了...
D10.天地弦 16:04:44
知道为什么吧...
D10.天地弦 16:04:58
这就是F7,F8的区别...
D10.天地弦 16:05:27
   
D10.天地弦 16:05:49
这两个Btn都是通过调用DLL内的函数来服务的...
D10.天地弦 16:06:14
现在我们来看看BtnGetFormNo是怎么工作的...
D10.天地弦 16:06:37
先看看主程序里,是调用的什么涵数...
 
D10.天地弦 16:06:47
procedure TFMainForm.btnGetFormNoClick(Sender: TObject);
begin
  edtFormNo.Text := FDebugIntf.RandomFormNo;
end;
D10.天地弦 16:06:54
来了没有?
D10.天地弦 16:07:12
可以发现是
  edtFormNo.Text := FDebugIntf.RandomFormNo;
D10.天地弦 16:07:23
调用的是RandomFormNo这个方法...
D10.天地弦 16:07:41
那我们在RandomFormNo中设置一个断点..
 
 
D10.天地弦 16:08:10
function TDebugService.RandomFormNo: WideString;
begin
  result := FDate + '-' + InnerGetRandom(999);
end;
 
D10.天地弦 16:08:26
运行程序
D10.天地弦 16:08:37
单击BtnGetFormNo按扭
D10.天地弦 16:08:50
就会在这里断了...
D10.天地弦 16:08:55
这样可以跟踪程序
D10.天地弦 16:09:06
如果DLL有错也是这样跟踪除错的....
D10.天地弦 16:09:37
有时候DLL内经常调试不到
D10.天地弦 16:10:04
大伙可以用ShowMessage的方法显示出值来看,只是麻烦一点...
D10.天地弦 16:10:13
完了,今天的课完了...
B6.银狼 16:10:25
3Q,D10
小小 16:10:28
嗯,也可以用Watch窗口看的
 B6.银狼 16:10:52
那就问点高级的 了
D10.天地弦 16:10:55
 嗯,是可以...
D10.天地弦 16:11:06
在for中间Watch用了...
小小 16:11:22
是啊 
D10.天地弦 16:11:34
下课...。自由活动...

转载于:https://www.cnblogs.com/DKSoft/articles/165272.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值