我正在使用一部旧的索尼爱立信手机开发一个用于编写和读取AT命令的小组件。在手机上发送和写入内容完全没有问题,但我希望能够暂停SendATCmd功能,等待COM端口组件用Notification Event通知我,然后再次恢复SendATCmd函数。
场景:我想获取手机中短信的数量。通常我会告诉电话:嘿,你有多少条短信?并且电话将在通知事件中回复。这一切都很好。
但我真正想做的是类似的事情
if SendATCmd('CountSMS')>0 then
for 0 to SMSCount do
AddSMSToList;
SendATCmd的代码如下:
function TSE_Z1010.SendATCmd(Cmd: string): TATResult;
begin
fCOMPort.PutString(Cmd); //Sending AT command
//Here is where I would like to pause this function
//wait for the fCOMPort to notify me when data is available
//and then resume this function again.
result:=fTMPATResult;
end;
我试过使用while循环、暂停等,但除了一件事之外,什么都没用,那就是我把ShowMessage放在应该暂停的地方。我不知道ShowMessage内部是如何工作的,但它似乎不会像while循环和pause那样停止程序。
====================
修复它。
我所要做的就是在use子句中添加Forms,然后添加while fTMPesult.Full=false do Application.ProcessMessages;在我想暂停程序的部分。
"fTMPesult"是在组件内全局存储传入COM端口数据的变量。
虽然AsyncPro确实有一些解决方案(控制数据),但它们是基于事件的,使代码难以阅读/理解。
这是带有AsyncPro的SendAndWaitForResponse(就像雷米建议的那样):
TForm1 = class(TForm)
...
private
IOEvent : THandle; // used for IO events
IORx : string;
Comport : TapdComport;
...
procedure TForm1.ComportTriggerAvail(CP: TObject; Count: Word);
var i : integer;
begin
for i:=1 to Count do
IORx:=IORx+Comport.GetChar;
SetEvent(IOEvent);
end;
function TForm1.SerialSAWR(tx : string; TimeOut : integer) : boolean;
begin
Result := False;
try
IORx := ''; // your global var
ResetEvent(IOEvent);
Comport.PutString(tx);
Result := WaitForSingleObject(IOEvent, TimeOut) = WAIT_OBJECT_0;
except
on E : Exception do
// dosomething with exception
end;
end;
// constructor part
IOEvent := CreateEvent(nil, True, False, nil);
// destructor part
if IOEvent <> 0 then
CloseHandle(IOEvent);
最好的解决方案是用comport创建一个线程,这样您的GUI就不会被阻塞。我用这种方式在生产中使用Asyncpro有几个应用程序,它的工作方式很有魅力。。。
任何时候需要手动调用Application.ProcessMessages()
,都需要重新思考代码设计。当在循环中调用它时,情况会加倍。
我不知道AsynchPro是如何工作的,但Win32 API有一个WaitCommEvent()
函数,可以满足您的要求。调用该函数以请求串行端口通知所需事件,然后可以使用WaitForOverlappedResult()
或WaitForSingleObject()
等待这些事件实际发生,具体取决于串行端口是否在重叠模式下运行。不需要进行消息处理。如果Asynch Pro没有以某种方式公开该功能,我会感到惊讶。