救命啊。十万火急。怎样编写利用通讯串口传输二进制文件(内附传输字符串源码)(200分)

  • 主题发起人 主题发起人 szdoudou1
  • 开始时间 开始时间
S

szdoudou1

Unregistered / Unconfirmed
GUEST, unregistred user!
现在只能传输文本格式的文件,也就是怎样才能传输.exe的文件。很急的。。忘能帮手。
源码如下


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;

const
WM_COMMNOTIFY=WM_USER +1; //自定义通信消息,通知主线程接收数据

type
TForm1 = class(TForm)
ViewData: TRichEdit;
OpenDataBtn: TButton;
SendDataBtn: TButton;
Label3: TLabel;
Label1: TLabel;
RcvDataBtn: TButton;
StopAllBtn: TButton;
ExitBtn: TButton;
OpenDialog1: TOpenDialog;
BpsSel: TComboBox;
Label2: TLabel;
Label4: TLabel;
ComPortSel: TComboBox;
Label5: TLabel;
BitSel: TComboBox;
StatusBar1: TStatusBar;
procedure OpenDataBtnClick(Sender: TObject);
procedure SendDataBtnClick(Sender: TObject);
procedure RcvDataBtnClick(Sender: TObject);
procedure StopAllBtnClick(Sender: TObject);
procedure ExitBtnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
procedure WMCOMMNOTIFY(var Message:TMessage);
message WM_COMMNOTIFY;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
var
hNewCommFile,Post_Event:THandle;//串口句柄、监视PostMessage事件
Read_os:Toverlapped;//读数据异步通讯结构
Receive:Boolean;//接收数据标志
dwEvtMask,ReceiveData:Dword;//接收数据大小

//将接收到的数据显示到数据显示区
//模块编号:M-1
procedure AddToMemo(Str:PChar;Len:Dword);
begin
str[Len]:=#0;
Form1.ViewData.text:=Form1.ViewData.Text+StrPas(str);
end;

//串口侦听模块
//模块编号:M-2
procedure CommWatch(Pstr:Pointer);stdcall;
var
dwTranser:Dword;
OK:Boolean;
Os:Toverlapped;//异步通讯结构
begin
Receive:=True; //打开侦听标志
FillChar(Os,SizeOf(Os),0);//填充异步通讯结构
//创建异步通讯事件
Os.hEvent:=CreateEvent(nil,True,False,nil);

//M-2:W-1
if Os.hEvent=null then
begin
MessageBox(0,'创建事件出错!','出错',MB_OK);
exit;
end;

//设置串口监控数据进入事件
//M-2:W-2
if (not SetCommMask(hNewCommFile,EV_RXCHAR)) then
begin
MessageBox(0,'设置串口监控事件出错!','设置串口监控事件出错',MB_OK);
exit;
end;
while(Receive) do
begin
dwEvtMask:=0;//初始化数据接收标志

//等待串口事件
if not WaitCommEvent(hNewCommFile,dwEvtMask,@Os) then
begin
if ERROR_IO_PENDING=GetLastError then
GetOverLappedResult(hNewCommFile,Os,dwTranser,true)

end;
//如果串口有数据进入则发用户消息给主线程,通知主线程接收数据
if dwEvtMask=EV_RXCHAR then
begin
//发送用户消息给主线程
OK:=PostMessage(Form1.Handle,WM_COMMNOTIFY,hNewCommFile,0);

//等待消息处理
WaitForSingleObject(Post_event,INFINITE);

//复位消息发送标志
ResetEvent(Post_Event);

//M-2:W-3
if (not OK) then
begin
MessageBox(0,'发送WM消息错误','错误',MB_OK);
exit;
end;
end;
CloseHandle(Os.hEvent);
end;
end;

//用户自定义消息,接收数据
//模块编号:M-3
procedure TForm1.WMCOMMNOTIFY(var Message:TMessage);
var
CommState:ComStat; //串口状态
dwNumberOfBytesRead:DWord;
ErrorFlag:Dword;//错误标志
InputBuffer:Array[0..1024] of Char;//输入缓冲区
begin
Label1.Font.Color:=clRed;
Label1.Caption:='正在接收数据...';
//清除输入缓冲区,准备接收数据
//M-3:W-1
if not ClearCommError(hNewCommFile,ErrorFlag,@CommState) then
begin
MessageBox(0,'清除输入输出缓冲区出错','清除输入输出缓冲区出错',MB_OK);
//通知串口放弃接收数据,并清空缓冲区
PurgeComm(hNewCommFile,Purge_Rxabort or Purge_Rxclear);
exit;
end;
//如果缓冲区的数据不为空则开始处理接收数据
if (CommState.cbInQue>0) then
begin
//填充输入缓冲区
fillchar(InputBuffer,CommState.cbInQue,#0);

//从串口读取数据到输入缓冲区
if (not ReadFile(hNewCommFile,InputBuffer,CommState.cbInQue,dwNumberOfBytesRead,@Read_Os)) then
begin
//获取标志
ErrorFlag:=GetLastError();
//M-3:W-2
if (ErrorFlag<>0) and (ErrorFlag<>ERROR_IO_PENDING) then
begin
MessageBox(0,'接收数据错误!','错误',MB_OK);
Receive:=false;
CloseHandle(Read_Os.hEvent);
CloseHandle(Post_Event);
CloseHandle(hNewCommFile);
exit;
end
else
begin
//等待串口接收数据
WaitForSingleObject(hNewCommFile,INFINITE);

GetOverlappedResult(hNewCommFile,Read_Os,dwNumberOfBytesRead,False);
end;
end;
//数据接收完毕,并显示数据到显示区域
if dwNumberOfBytesRead<>0 then
begin
Read_Os.Offset:=Read_Os.Offset+dwNumberOfBytesRead;
ReceiveData:=Read_Os.Offset;
AddToMemo(InputBuffer,dwNumberOfBytesRead);
end;
end;
//设置发送消息标志,通知侦听线程,消息处理完毕
SetEvent(Post_Event);
end;

//打开将发送的文件
//模块编号:M-4
procedure TForm1.OpenDataBtnClick(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
RcvDataBtn.Enabled:=false; //接收数据按钮失效
StopAllBtn.Enabled:=false; //停止处理按钮失效
ViewData.Lines.LoadFromFile(OpenDialog1.FileName);//数据显示区从打开对话框选择的文件打开并显示文件
Form1.Caption:=IntToStr(ViewData.GetTextLen);//窗口标题计算待发送数据总共字节数
end;
OpenDataBtn.Enabled:=false;//打开文件按钮失效
end;

//发送数据处理子模块
//模块编号:M-5
procedure TForm1.SendDataBtnClick(Sender: TObject);
var
dcb:TDCB; //Delphi串口编程封装
Error:Boolean;//Bool变量,用于判断设置串口函数返回值
dwNumberOfBytesWritten,dwNumberOfBytesToWrite,ErrorFlag,dwWhereToStartWriting:DWORD;
pDataToWrite:PChar;
Write_Os:Toverlapped;//异步通讯数据类型
begin
//判断是否正在接收数据,如果是则等待数据接收完成,否则暂停侦听,发送数据。
//M-5:W-1
if dwEvtMask=EV_RXCHAR then
begin
MessageBox(0,'串口正在接收数据,请稍后再试!','设备忙',MB_OK);
exit;
end
else
begin
//停止侦听。
StopAllBtn.Click;
end;
SendDataBtn.Enabled:=false; //使发送数据按钮失效
StatusBar1.SimpleText:='正在发送数据...';
Form1.Caption:='';//清除窗口标题显示
//以异步通讯方式打开串口
hNewCommFile:=CreateFile(Pchar(ComPortSel.text),GENERIC_WRITE,0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
//M-5:W-2
if hNewCommFile=INVALID_HANDLE_VALUE then
begin
MessageBox(0,'打开通信端口错误!','错误',MB_OK);
exit;
end;

//设置缓冲区大小及主要通信参数
SetupComm(hNewCommFile,1024,1024);
//获取当前串口基本配置信息(波特率、数据位等)
GetCommState(hNewCommfile,dcb);

//以用户选择方式设置串口配置信息
dcb.BaudRate:=StrToInt(BpsSel.Text);
dcb.ByteSize:=StrToInt(BitSel.Text);
dcb.StopBits:=ONESTOPBIT;
dcb.fBinary:=TRUE;
Error:=SetCommState(hNewCommFile,dcb);
//M-5:W-3
if (not Error) then
begin
MessageBox(0,'设置通信端口参数错误!','错误',MB_OK);
exit;
end;

dwWhereToStartWriting:=0;//初始化变量(待发数据发送开始位置)
dwNumberOfBytesWritten:=0; //初始化变量(已经发送多少数据)
dwNumberOfBytesToWrite:=ViewData.GetTextLen;//初始化变量(待发送数据长度)

//判断待传数据不能为空
//M-5:W-4
if (dwNumberOfBytesToWrite=0) then
begin
ShowMessage('不能传输空数据!');
exit;
end
else
begin
pDataToWrite:=StrAlloc(dwNumberOfBytesToWrite+1);
try
ViewData.GetTextBuf(pDataToWrite,dwNumberOfBytesToWrite);
Label1.Font.Color:=clRed;

//填充异步通讯结构
FillChar(Write_Os,SizeOf(Write_Os),0);

//创建监视发送数据事件
Write_Os.hEvent:=CreateEvent(nil,True,False,nil);
//设置串口句柄监视发送数据事件
SetCommMask(hNewCommFile,EV_TXEMPTY);

Label1.Caption:='正在发送数据...';
repeat
label1.Repaint;
//使用异步通讯方式发送数据
if not WriteFile(hNewCommFile,pDataToWrite[dwWhereToStartWriting],dwNumberOfBytesToWrite,dwNumberOfBytesWritten,@Write_Os) then
begin
//获得错误标志
ErrorFlag:=GetLastError;
if ErrorFlag<>0 then
begin
if ErrorFlag=ERROR_IO_PENDING then
begin
//一直等待写操作标志被改变
WaitForSingleObject(Write_Os.hEvent,INFINITE);

GetOverlappedResult(hNewCommFile,Write_Os,dwNumberOfBytesWritten,False);
end
else
//M-5:W-5
begin
MessageBox(0,'发送数据错误!','错误',MB_OK);
CloseHandle(Write_Os.hEvent);
CloseHandle(hNewCommFile);
exit;
end;
end;
end;
Dec(dwNumberOfBytesToWrite,dwNumberOfBytesWritten);
Inc(dwWhereToStartWriting,dwNumberOfBytesWritten);

until(dwNumberOfBytesToWrite<=0);
Form1.Caption:=IntToStr(dwWhereToStartWriting);
finally
StrDispose(pDataToWrite);
end;
CloseHandle(hNewCommFile);
end;
Label1.Font.Color:=clBlack;
Label1.Caption:='发送成功!';
CloseHandle(Write_Os.hEvent);
OpenDataBtn.Enabled:=true;//使打开文件按钮生效
RcvDataBtn.Enabled:=true; //使接收文件按钮生效
StopAllBtn.Enabled:=true; //使停止处理按钮生效
SendDataBtn.Enabled:=true; //使发送数据按钮生效
RcvDataBtn.Click;//启动侦听
end;

//启动侦听子模块,侦听初始化处理
//模块编号:M-6
procedure TForm1.RcvDataBtnClick(Sender: TObject);
var
OK:Boolean;
dcb:TDCB;
com_thread:Thandle;
ThreadID:DWORD;
begin
ReceiveData:=0; //初始化已经接收数据变量
// OpenDataBtn.Enabled:=false; //使打开文件按钮失效
// SendDataBtn.Enabled:=false; //使发送数据按钮失效
ViewData.Clear; //清除数据显示区已有数据

//打开串口,使用异步通讯方式。
hNewCommFile:=CreateFile(Pchar(ComPortSel.text),GENERIC_READ,0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);

//如果返回INVALID_HANDLE_VALUE则显示出错信息。
//M-6:W-1
if hNewCommFile=INVALID_HANDLE_VALUE then
begin
MessageBox(0,Pchar('打开串口'+ComPortSel.text+'错误!'),'错误',MB_OK);
exit;
end;

//设置串口输入输出缓冲区大小
SetupComm(hNewCommFile,1024,1024);

//获得当前串口配置信息
GetCommState(hNewCommFile,dcb);
//以用户选择方式设置串口基本信息(波特率、数据位等)
dcb.BaudRate:=StrToInt(BpsSel.Text);
dcb.ByteSize:=StrToInt(BitSel.Text);
dcb.StopBits:=ONESTOPBIT;
Ok:=SetCommState(hNewCommFile,dcb);
//M-6:W-2
if (not Ok) then
begin
MessageBox(0,'设置参数出错!','错误',MB_OK);
exit;
end;
//设置串口监视接收事件
OK:=SetCommMask(hNewCommFile,EV_RXCHAR);

//M-6:W-3
if (not OK) then
begin
MessageBox(0,'设置串口监视事件出错!','设置串口监视事件出错!',MB_OK);
exit;
end;
//填充读串口异步通讯结构
FillChar(Read_Os,SizeOf(Read_Os),0);
Read_Os.Offset:=0;
Read_Os.OffsetHigh:=0;

//创建读串口操作事件
Read_Os.hEvent:=CreateEvent(nil,true,false,nil);

//M-6:W-4
if Read_Os.hEvent=null then
begin
Closehandle(hNewCommFile);
MessageBox(0,'创建日志错误!','错误',MB_OK);
exit;
end;

//创建PostMessage监控事件
Post_Event:=CreateEvent(nil,True,False,nil);
//M-6:W-5
if Post_Event=null then
begin
CloseHandle(hNewCommFile);
CloseHandle(Read_Os.hEvent);
MessageBox(0,'创建日志错误!','错误',MB_OK);
exit;
end;

//创建侦听线程
Com_Thread:=CreateThread(nil,0,@CommWatch,nil,0,ThreadID);

//M-6:W-6
if (Com_Thread=0) then
begin
MessageBox(0,'创建侦听线程出错!','错误',MB_OK);
exit;
end;
EscapeCommFunction(hNewCommFile,SETDTR);
// Label1.Font.Color:=clRed;
// Label1.Caption:='正在接收数据...';
StatusBar1.SimpleText:='侦听串口中...';
end;

//停止通讯子模块
//模块编号:M-7
procedure TForm1.StopAllBtnClick(Sender: TObject);
begin
Label1.Font.Color:=clBlack;
Label1.Caption:='已停止通信';
StatusBar1.SimpleText:='通讯已停止...';
//更改窗口标题为已收到数据字节数
Form1.Caption:=IntToStr(ReceiveData);
//标记接收标志为false
Receive:=false;
//关闭读串口操作句柄
CloseHandle(Read_Os.hEvent);
//关闭监视PostMessage事件句柄
Closehandle(Post_Event);
//关闭串口句柄
CloseHandle(hNewCommFile);
//使打开文件按钮生效
OpenDataBtn.Enabled:=true;
//使发送数据按钮生效
SendDataBtn.Enabled:=true;
Sleep(1000);
end;

//退出
//模块编号:M-8
procedure TForm1.ExitBtnClick(Sender: TObject);
begin
Form1.Close;
end;

//启动程序进入侦听状态。
//模块编号:M-9
procedure TForm1.FormCreate(Sender: TObject);
begin
RcvDataBtn.Click;
end;

//程序退出,关闭相关句柄,释放内存
//模块编号:M-10
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
StopAllBtn.Click;
end;

end.
 
希望能给个例子。谢谢了。。~我的QQ :10235
 
帮下忙,真的很急!
 
后退
顶部