您的位置:首页 > 编程语言 > Delphi

Delphi:TComPort封装在DLL中,通讯时无法接收串口数据的解决办法

2008-06-25 10:13 609 查看
现象:
将Tcomport(版本:ComPort Library ver. 3.0 )封装在DLL中,进行串口通讯时,无法接收数据!

解决办法:
在创建组件时,只需要更改一个属性的设置就可以了。如下所示:
//DLL入口

talencaport:=ttalencaport.Create(nil);
talencaport.port:='COM1';
talencaport.SyncMethod:=smWindowSync;
talencaport.OnRxChar:=talencaport.readbuf;
红色加粗的代码就是关键的一句代码!加入此句代码后,在DLL中发送与接收数据就与在窗体上使用一样。

分析:
由于工作需要,一直使用DELPHI5,DELPHI7两个版本进行开发。在DELPHI5中,将TCOMPORT封装在DLL中使用,没有任何的异常。后来抱成DELPHI7后,当时以为,同样的代码,应当没有什么问题。于是,编译。成功!哈!原来版本升级这么容易!也没有多想,没有测试,就把这事情放在了脑后。-_-!!

时间过了一个月,公司有设备要进行测试,因此,自己很高兴地把新的东西用来测试,结果,所有的通讯指令均是失败(无数据)!头顿时就要炸了。。。。。。

还好,是自己测试,有问题还算是可以补救的。仔细看源码,与DELPHI5下的源码是一样的,为什么在DELPHI7下就接收不到数据呢?看来问题还是在TCOMPORT本身上。(:),偶还是粉相信DELPHI实力的!:))
一看DLL入口代码:
talencaport:=ttalencaport.Create(nil);
talencaport.port:='COM1';
talencaport.OnRxChar:=talencaport.readbuf;
似乎也看不出什么问题来。

心想,是不是在发送完数据后,要延时一点时间呢,于是在发送完数据后,加入一个延时100ms和小过程(这个延时时间跟我们的设备相关),结果发现还是收不到数据。看来不是这个延时的问题。
延时过程代码:
var Com_waittime:cardinal;
Com_waittime:=gettickcount;
While gettickcount- Com_waittime<100 do application.processmessages;

没有办法,只能看TCOMPORT源码了。一看源码,TCOMPORT的收数据是由线程完成的。相应线程类是:TcomThread;因此,决定看看线程优先级。哦,是tpNormal.那调高这个优先级会不会有所改善?改成tohigher,tphighest…问题依然!看来与线程优先级无关。
再仔细研究这个线程的代码,
TComThread = class(TThread)
private
FComPort: TCustomComPort;
FStopEvent: THandle;
FEvents: TComEvents;
protected
procedure DispatchComMsg;
procedure DoEvents;
procedure Execute; override;
procedure SendEvents;
procedure Stop;
public
constructor Create(AComPort: TCustomComPort);
destructor Destroy; override;
end;

从Execute入口,得知:线程内部是利用了系统事件对象完成对串口数据接收的触发。当收到事件后,把系统对应的事件保存在组合的属性中。

TComEvent = (evRxChar, evTxEmpty, evRxFlag, evRing, evBreak, evCTS, evDSR,
evError, evRLSD, evRx80Full);
TComEvents = set of TComEvent;

// if event occurs, dispatch it
if (Signaled = WAIT_OBJECT_0 + 1)
and GetOverlappedResult(FComPort.Handle, Overlapped, BytesTrans, False)
then
begin
//
FEvents := IntToEvents(Mask);
DispatchComMsg;
end;

从蓝色的代码可知:当发生串口事件时,保存事件类型,然后就分发事件,找对应的事件来执行这个接收过程了。于是再看DispatchComMsg方法:
// dispatch events
procedure TComThread.DispatchComMsg;
begin
case FComPort.SyncMethod of
smThreadSync: Synchronize(DoEvents); // call events in main thread
smWindowSync: SendEvents; // call events in thread that opened the port
smNone: DoEvents; // call events inside monitoring thread
end;
end;

在doEvents这个同步方法中,无法执行相应的事件。从注释来看,是指在主线程中执行这个操作,由于此时是封装在DLL中,没有主线程存在,因此,这个方法的执行也就是石沉大海了。这就是无法接收数据的原因了。

而第二个项就是:调用打开串口的线程对应事件。看来这个有戏。因此,将组件线程的同步方法类型改成smWindowSync
果然,接收数据正常。

对于第三个选项:在监视线程中执行事件,本人没有测试,因为时间关系。。。。。哎,有兴趣的DELPHIER可以试试。。。。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐