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可以试试。。。。。。。
将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可以试试。。。。。。。
相关文章推荐
- dataTable 发送数据使用springMVC接收自动封装失败的解决办法
- MFC串口发送数据大于128数据出错的解决办法(发送0xFE接收得到0x3F等问题)
- 宽带能连接上,接收不到数据或局域网内某台电脑的共享资源无法访问解决办法
- STM32F107VC的ETH以太网外设+DP83848无法发送和接收数据包的解决办法
- LPC17XX串口接收数据死机现象解决办法
- MySQL问题贴3:Delphi第一次编译连接MySQl数据时缺少dll文件的解决办法
- 解决使用MSComm控件进行串口数据的接收数据不完整
- MFC使用Unicode字符集在网络编程接收数据乱码或不完整的解决办法
- [无法计算项元数据“%(FullPath)” 无法将项元数据“%(FullPath)”应用于路径] 问题解决办法
- EasyUI学习笔记(1)----Tree控件实现过程中.NET下无法访问json数据的解决办法
- [转载]无法删除oci.dll文件的解决办法
- Delphi 2005帮助文档无法使用的解决办法
- socket接收服务器数据,输出为乱码或无法输出的解决方法
- 无法定位序数XX于动态链接库XX.dll的解决办法
- ORA-01653 无法在表空间扩展的解决办法 -- 增加表空间大小或给表空间增加数据文件
- c#调用c++封装dll 参数为字符串输出函数的解决办法
- C#中请问如何在串口通讯中接收输出HEX格式数据
- ABB机器人添加串口模块后无法使用的解决办法
- Android Wear开发 - 数据通讯 - 第四节 : 数据封装(解决不能序列化问题)
- 关于无法加载DLL"***.dll":找不到指定的模块(异常来自HRESULT:0x8007007E)问题的解决办法