问题描述:基本上这是一个手机用COM串口通讯的来电显示程序,但是现在就是程序运行后,SETCOMMSTATE失败,跟踪后发现READFILE与WRITEFILE失败。但是如果手动运行WINDOWS的超级终端,并与手机连接,断开后,在运行程序,就能在MEMO中显示来电了,解决不了啊。各位大哥们帮忙啊,这是我工作叫给我的第一个问题。我是个新手,就靠各位大哥了!!!(部分代码没写进去,估计各位大哥也应该想的出来)
部分代码如下
procedure TForm1.Button1Click(Sender: TObject);
var
lpdcb: TDCB;
Ini: TIniFile;
com: string;
fdwattrsandflags:DWORD;
begin
if Opened then
Exit;
Ini := TIniFile.Create(apppath + 'config.ini');
// com:=Ini.ReadString('HW','Port','');
// IF com='' Then
Com := ComboBox1.Text;
ComboBox1.ItemIndex := ComboBox1.Items.IndexOf(COM);
hCom := CreateFile(Pchar(ComboBox1.Text), generic_read or
generic_write, 0, nil, open_existing,
file_attribute_normal or
file_flag_overlapped, 0);
if hCom = INVALID_HANDLE_VALUE then
begin
Ini.Free;
Exit;
end;
Opened := True;
SetupComm(hCom,4096,4096);
PurgeComm(hCom,PURGE_RXCLEAR );
GetCommState(hcom, lpdcb);
lpdcb.baudrate :=19200;
lpdcb.StopBits := 1;
lpdcb.ByteSize := 8;
lpdcb.Parity:=NoParity;
Setcommstate(hcom, lpdcb);
SetcommMask(hcom, EV_RXCHAR);
Ini.WriteString('HW', 'PORT', ComboBox1.Text);
Ini.Free;
//SendCMD('AT+VCID=1');
SendCMD('AT+CLIP=1');
end;
constructor TComThread.Create(Handle: DWORD; HWND: DWORD);
begin
FhCom := Handle;
FHWND := HWND;
FExit := False;
post_event:=CreateEvent(nil,true,true,nil);
read_os.hEvent:=CreateEvent(NIL,TRUE,true,NIL);
write_os.hEvent:=CreateEvent(NIL,TRUE,true,NIL);
read_os.Offset:=0;
read_os.OffsetHigh:=0;
write_os.Offset:=0;
write_os.OffsetHigh:=0;
inherited Create(False);
FreeOnTerminate := True;
end;
procedure TComThread.Execute;
var
dwEvtMask: Dword;
Wait: Boolean;
begin
fillchar(lpol, sizeof(toverlapped), 0);
while True do
begin
dwEvtMask := 0;
Wait := WaitCommEvent(Fhcom, dwevtmask, nil);
if Wait then
begin
waitforsingleobject(post_event, infinite);
resetevent(post_event);
PostMessage(FHWND, WM_COMMNOTIFY, 0, 0);
end
else
Exit;
end;
end;
procedure TForm1.SendCMD(CMD: string);
var
Buffer: array[0..127] of char;
cbNum: DWORD;
begin
Fillchar(Buffer, 128, 0);
CMD := CMD + #$0D#$0A;
StrCopy(@Buffer, Pchar(CMD));
fillchar(lpol, sizeof(toverlapped), 0);
ComThread := TComThread.Create(hCom, Handle);
WriteFile(hCom, Buffer, Length(CMD), cbNum, @lpol);
end;
procedure TForm1.MsgComProcess(var Message: Tmessage);
var
Clear: Boolean;
Coms: Tcomstat;
cbNum, ReadNumber, lpErrors: DWORD;
Read_Buffer: array[1..100] of char;
iPos, Pos2: Integer;
Num: Pchar;
tmpstr: string;
begin
Clear := Clearcommerror(hcom, lpErrors, @Coms);
if Clear then
begin
cbNum := Coms.cbInQue;
FillChar(Read_Buffer, 100, 0);
Sleep(100);
ReadFile(hCom, Read_Buffer, cbNum, ReadNumber, @lpol;
SetEvent(Post_Event);
end;
部分代码如下
procedure TForm1.Button1Click(Sender: TObject);
var
lpdcb: TDCB;
Ini: TIniFile;
com: string;
fdwattrsandflags:DWORD;
begin
if Opened then
Exit;
Ini := TIniFile.Create(apppath + 'config.ini');
// com:=Ini.ReadString('HW','Port','');
// IF com='' Then
Com := ComboBox1.Text;
ComboBox1.ItemIndex := ComboBox1.Items.IndexOf(COM);
hCom := CreateFile(Pchar(ComboBox1.Text), generic_read or
generic_write, 0, nil, open_existing,
file_attribute_normal or
file_flag_overlapped, 0);
if hCom = INVALID_HANDLE_VALUE then
begin
Ini.Free;
Exit;
end;
Opened := True;
SetupComm(hCom,4096,4096);
PurgeComm(hCom,PURGE_RXCLEAR );
GetCommState(hcom, lpdcb);
lpdcb.baudrate :=19200;
lpdcb.StopBits := 1;
lpdcb.ByteSize := 8;
lpdcb.Parity:=NoParity;
Setcommstate(hcom, lpdcb);
SetcommMask(hcom, EV_RXCHAR);
Ini.WriteString('HW', 'PORT', ComboBox1.Text);
Ini.Free;
//SendCMD('AT+VCID=1');
SendCMD('AT+CLIP=1');
end;
constructor TComThread.Create(Handle: DWORD; HWND: DWORD);
begin
FhCom := Handle;
FHWND := HWND;
FExit := False;
post_event:=CreateEvent(nil,true,true,nil);
read_os.hEvent:=CreateEvent(NIL,TRUE,true,NIL);
write_os.hEvent:=CreateEvent(NIL,TRUE,true,NIL);
read_os.Offset:=0;
read_os.OffsetHigh:=0;
write_os.Offset:=0;
write_os.OffsetHigh:=0;
inherited Create(False);
FreeOnTerminate := True;
end;
procedure TComThread.Execute;
var
dwEvtMask: Dword;
Wait: Boolean;
begin
fillchar(lpol, sizeof(toverlapped), 0);
while True do
begin
dwEvtMask := 0;
Wait := WaitCommEvent(Fhcom, dwevtmask, nil);
if Wait then
begin
waitforsingleobject(post_event, infinite);
resetevent(post_event);
PostMessage(FHWND, WM_COMMNOTIFY, 0, 0);
end
else
Exit;
end;
end;
procedure TForm1.SendCMD(CMD: string);
var
Buffer: array[0..127] of char;
cbNum: DWORD;
begin
Fillchar(Buffer, 128, 0);
CMD := CMD + #$0D#$0A;
StrCopy(@Buffer, Pchar(CMD));
fillchar(lpol, sizeof(toverlapped), 0);
ComThread := TComThread.Create(hCom, Handle);
WriteFile(hCom, Buffer, Length(CMD), cbNum, @lpol);
end;
procedure TForm1.MsgComProcess(var Message: Tmessage);
var
Clear: Boolean;
Coms: Tcomstat;
cbNum, ReadNumber, lpErrors: DWORD;
Read_Buffer: array[1..100] of char;
iPos, Pos2: Integer;
Num: Pchar;
tmpstr: string;
begin
Clear := Clearcommerror(hcom, lpErrors, @Coms);
if Clear then
begin
cbNum := Coms.cbInQue;
FillChar(Read_Buffer, 100, 0);
Sleep(100);
ReadFile(hCom, Read_Buffer, cbNum, ReadNumber, @lpol;
SetEvent(Post_Event);
end;
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;type
TForm1 = class(TForm)
rdCOM: TRadioGroup;
Label1: TLabel;
Label2: TLabel;
btnOpenPort: TButton;
btnEnd: TButton;
spCD: TShape;
spDSR: TShape;
spCTS: TShape;
Label3: TLabel;
Label4: TLabel;
spRI: TShape;
Timer1: TTimer;
procedure btnOpenPortClick(Sender: TObject);
procedure btnEndClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
DTRState:Boolean;
RTSState:Boolean;
DOValue:DWORD;
public
{ Public declarations }
procedure OpenComm; //打开通信端口
end;var
Form1: TForm1;
hComm: THandle;implementation{$R *.DFM}//以下是打开通信端口的程序
procedure TForm1.btnOpenPortClick(Sender: TObject);begin
//若通信端口已打开,则不需要再打开
if (hComm<>0) then begin
ShowMessage('通信端口已打开!不需再开!');
exit;
end;
OpenComm; //打开通信端口的子程序
//先将DTR/RTS的电压降成低电压
EscapeCommFunction( hComm, CLRDTR); //将DTR降为低电压
EscapeCommFunction( hComm, CLRRTS); //将RTS降为低电压
end;//以下是打开通信端口的实际程序代码,采用API
procedure TForm1.OpenComm;
var
cc:TCOMMCONFIG; //定义通信组态变量
Temp:string;
begin
// 选择所要打开的COM
Temp:='COM'+inttostr(rdcom.ItemIndex+1);
// 以Create函数打开COM
hComm:=CreateFile(PChar(Temp), GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING, 0, 0);
// 判断COM 是否顺利打开
if (hComm = INVALID_HANDLE_VALUE) then begin
MessageBox (0, '打开通信端口错误!!','',MB_OK);
exit;
end;
//以下设置通信端口的参数
GetCommState(hComm,cc.dcb); // 得知目前COM 的状态
cc.dcb.BaudRate:=CBR_9600; // 设置波特率为9600
cc.dcb.ByteSize:=8; // 字节为 8 bit
cc.dcb.Parity:=NOPARITY; // Parity 为 None
cc.dcb.StopBits:=ONESTOPBIT; // 1 个Stop bit
//若分别控制DTR、RTS,必须不能激活HandShaking
cc.dcb.Flags:=1; //此动作可关闭HandShaking等设置
//以下将通信端口参数写入实际硬件
if not SetCommState(hComm, cc.dcb) then begin // 设置COM 的状态
MessageBox (0, '通信端口设置错误!!!','',MB_OK);
CloseHandle(hComm);
exit;
end;
end;//以下是结束按钮的动作
procedure TForm1.btnEndClick(Sender: TObject);
begin
SetCommMask(hcomm,$0); //取消所有的事件设定
CloseHandle(hComm); //关闭通信端口
close; //结束程序
end;//窗体建立时的初值设定
procedure TForm1.FormCreate(Sender: TObject);
begin
RTSState:=False; //预设是低电压
DTRState:=False; //预设是低电压
end;procedure TForm1.Timer1Timer(Sender: TObject);
var
lStatus:DWORD; //输入线路状态变量
begin
if (hComm =0) then exit ;
if GetCommModemStatus(hComm,lStatus) then
begin
//检查CTS状态
if ( lStatus and MS_CTS_ON )= MS_CTS_ON then
spCTS.Brush.Color :=clRed
else spCTS.Brush.Color :=clWhite;
//检查DSR状态
if ( lStatus and MS_DSR_ON )=MS_DSR_ON then
spDSR.Brush.Color :=clRed
else spDSR.Brush.Color :=clWhite;
//检查RI状态
if ( lStatus and MS_RING_ON )=MS_RING_ON then
spRI.Brush.Color :=clRed
else spRI.Brush.Color :=clWhite;
//检查CD状态
if ( lStatus and MS_RLSD_ON )=MS_RLSD_ON then
spCD.Brush.Color :=clRed
else spCD.Brush.Color :=clWhite;
end;
end;end.
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;type
TForm1 = class(TForm)
rdCOM: TRadioGroup;
Label1: TLabel;
Label2: TLabel;
btnOpenPort: TButton;
btnEnd: TButton;
spDTR: TShape;
spRTS: TShape;
btnDTR: TButton;
btnRTS: TButton;
procedure btnOpenPortClick(Sender: TObject);
procedure btnEndClick(Sender: TObject);
procedure btnDTRClick(Sender: TObject);
procedure btnRTSClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
DTRState:Boolean;
RTSState:Boolean;
DOValue:DWORD;
public
{ Public declarations }
procedure OpenComm; //打开通信端口
end;var
Form1: TForm1;
hComm: THandle;implementation{$R *.DFM}//以下是打开通信端口的程序
procedure TForm1.btnOpenPortClick(Sender: TObject);begin
//若通信端口已打开,则不需要再打开
if (hComm<>0) then begin
Messagedlg('通信端口已打开,不需再开',mtError,[mbOK],0);
exit;
end;
OpenComm; //打开通信端口的子程序
//先将DTR/RTS的电压降成低电压
EscapeCommFunction( hComm, CLRDTR); //将DTR降为低电压
EscapeCommFunction( hComm, CLRRTS); //将RTS降为低电压
end;//以下是打开通信端口的实际程序代码,采用API
procedure TForm1.OpenComm;
var
cc:TCOMMCONFIG; //定义通信组态变量
Temp:string;
begin
// 选择所要打开的COM
Temp:='COM'+inttostr(rdcom.ItemIndex+1);
// 以Create函数打开COM
hComm:=CreateFile(PChar(Temp), GENERIC_READ or GENERIC_WRITE,
0, nil, OPEN_EXISTING, 0, 0);
// 判断COM 是否顺利打开
if (hComm = INVALID_HANDLE_VALUE) then begin
Messagedlg('打开通信端口错误!!',mtError,[mbOK],0);
exit;
end;
//以下设置通信端口的参数
GetCommState(hComm,cc.dcb); // 得知目前COM 的状态
cc.dcb.BaudRate:=CBR_9600; // 设置波特率为9600
cc.dcb.ByteSize:=8; // 字节为 8 bit
cc.dcb.Parity:=NOPARITY; // Parity 为 None
cc.dcb.StopBits:=ONESTOPBIT; // 1 个Stop bit
//若分别控制DTR、RTS,必须不能激活HandShaking
cc.dcb.Flags:=1; //此动作可关闭HandShaking等设置
//以下将通信端口参数写入实际硬件
if not SetCommState(hComm, cc.dcb) then begin // 设置COM 的状态
MessageBox (0, '通信端口设置错误!!!','',MB_OK);
CloseHandle(hComm);
exit;
end;
end;//以下是结束按钮的动作
procedure TForm1.btnEndClick(Sender: TObject);
begin
CloseHandle(hComm); //关闭通信端口
close; //结束程序
end;//以下是控制DTR状态的按钮程序
procedure TForm1.btnDTRClick(Sender: TObject);
begin
//若通信端口未打开,则不作动作,并跳出
if (hComm=0) then begin
Messagedlg('通信端口未打开!!',mtError,[mbOK],0);
exit;
end;
//判断DTRState值,输出状态后,将原值作转态
if DTRState then
begin
DOValue:=CLRDTR; //设置DTR为低电压
EscapeCommFunction( hComm, DOValue );//输出DTR状态
spDTR.Brush.Color:=clWhite; //变更灯号的颜色
end
else
begin
DOValue:=SETDTR; //设置DTR为高电压
EscapeCommFunction( hComm, DOValue );//输出DTR的状态
spDTR.Brush.Color:=clRed; //变更灯号的颜色
end;
DTRState:=(not DTRState); //将DTRState转态
end;//以下是控制RTS状态的按钮程序
procedure TForm1.btnRTSClick(Sender: TObject);
begin
//若通信端口未打开,则不作动作,并跳出
if (hComm=0) then begin
Messagedlg('通信端口未打开!!',mtError,[mbOK],0);
exit;
end;
//判断RTSState值,输出状态后,将原值作转态
if RTSState then
begin
DOValue:=CLRRTS; //设置RTS为低电压
EscapeCommFunction( hComm, DOValue );//输出RTS状态
spRTS.Brush.Color:=$FFFFFF;//变更灯号
end
else
begin
DOValue:=SETRTS; //设置RTS为高电压
EscapeCommFunction( hComm, DOValue );//输出RTS状态
spRTS.Brush.Color:=$00FF00;//变更灯号
end;
RTSState:=(not RTSState); //将RTSState转态
end;//窗体建立时的初值设置
procedure TForm1.FormCreate(Sender: TObject);
begin
RTSState:=False; //默认是低电压
DTRState:=False; //默认是低电压
end;
end.