http://www./keylife/iblog_show.asp?xid=23218 作者: walimg 标题: 请教MemoryStream的使用方法 (DEMO) 关键字: 分类: 个人专区 密级: 公开 (评分: , 回复: 0, 阅读: 39) »» 来自: ranjiao, 时间: 2005-08-15 18:45:00, ID: 3167898 我想用MemoryStream反复读取文件操作,但是我调用clear和free想清除内存的时候都会报错。。。 应该怎么弄? 来自: chenybin, 时间: 2005-08-15 20:24:58, ID: 3167929 先看看你的代码
http://www./delphibbs/modifyl.asp?lid=1474545
谈Delphi编程中“流”的应用
陈经韬 什么是流?流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向。流不但可以处理文件,还可以处理动态内存、网络数据等多种数据形式。如果你对流的操作非常熟练,在程序中利用流的方便性,写起程序会大大提高效率的。 下面,笔者通过四个实例:EXE文件加密器、电子贺卡、自制OICQ和网络屏幕传输来说明Delphi编程中“流”的利用。这些例子中的一些技巧曾经是很多软件的秘密而不公开的,现在大家可以无偿的直接引用其中的代码了。 “万丈高楼平地起”,在分析实例之前,我们先来了解一下流的基本概念和函数,只有在理解了这些基本的东西后我们才能进行下一步。请务必认真领会这些基本方法。当然,如果你对它们已经很熟悉了,则可以跳过这一步。
一、Delphi中流的基本概念及函数声明 在Delphi中,所有流对象的基类为TStream类,其中定义了所有流的共同属性和方法。 TStream类中定义的属性介绍如下: 1、Size:此属性以字节返回流中数据大小。 2、Position:此属性控制流中存取指针的位置。 Tstream中定义的虚方法有四个: 1、Read:此方法实现将数据从流中读出。函数原形为: Function Read(var Buffer;Count:Longint):Longint;virtual;abstract; 参数Buffer为数据读出时放置的缓冲区,Count为需要读出的数据的字节数,该方法返回值为实际读出的字节数,它可以小于或等于Count中指定的值。 2、Write:此方法实现将数据写入流中。函数原形为: Function Write(var Buffer;Count:Longint):Longint;virtual;abstract; 参数Buffer为将要写入流中的数据的缓冲区,Count为数据的长度字节数,该方法返回值为实际写入流中的字节数。 3、Seek:此方法实现流中读取指针的移动。函数原形为: Function Seek(Offset:Longint;Origint:Word):Longint;virtual;abstract; 参数Offset为偏移字节数,参数Origint指出Offset的实际意义,其可能的取值如下: soFromBeginning:Offset为移动后指针距离数据开始的位置。此时Offset必须大于或者等于零。 soFromCurrent:Offset为移动后指针与当前指针的相对位置。 soFromEnd:Offset为移动后指针距离数据结束的位置。此时Offset必须小于或者等于零。该方法返回值为移动后指针的位置。 4、Setsize:此方法实现改变数据的大小。函数原形为: Function Setsize(NewSize:Longint);virtual; 另外,TStream类中还定义了几个静态方法: 1、ReadBuffer:此方法的作用是从流中当前位置读取数据。函数原形为: Procedure ReadBuffer(var Buffer;Count:Longint); 参数的定义跟上面的Read相同。注意:当读取的数据字节数与需要读取的字节数不相同时,将产生EReadError异常。 2、WriteBuffer:此方法的作用是在当前位置向流写入数据。函数原形为: Procedure WriteBuffer(var Buffer;Count:Longint); 参数的定义跟上面的Write相同。注意:当写入的数据字节数与需要写入的字节数不相同时,将产生EWriteError异常。 3、CopyFrom:此方法的作用是从其它流中拷贝数据流。函数原形为: Function CopyFrom(Source:TStream;Count:Longint):Longint; 参数Source为提供数据的流,Count为拷贝的数据字节数。当Count大于0时,CopyFrom从Source参数的当前位置拷贝Count个字节的数据;当Count等于0时,CopyFrom设置Source参数的Position属性为0,然后拷贝Source的所有数据; TStream还有其它派生类,其中最常用的是TFileStream类。使用TFileStream类来存取文件,首先要建立一个实例。声明如下: constructor Create(const Filename:string;Mode:Word); Filename为文件名(包括路径),参数Mode为打开文件的方式,它包括文件的打开模式和共享模式,其可能的取值和意义如下:
打开模式: fmCreate :用指定的文件名建立文件,如果文件已经存在则打开它。 fmOpenRead :以只读方式打开指定文件 fmOpenWrite :以只写方式打开指定文件 fmOpenReadWrite:以写写方式打开指定文件 共享模式: fmShareCompat :共享模式与FCBs兼容 fmShareExclusive:不允许别的程序以任何方式打开该文件 fmShareDenyWrite:不允许别的程序以写方式打开该文件 fmShareDenyRead :不允许别的程序以读方式打开该文件 fmShareDenyNone :别的程序可以以任何方式打开该文件
TStream还有一个派生类TMemoryStream,实际应用中用的次数也非常频繁。它叫内存流,就是说在内存中建立一个流对象。它的基本方法和函数跟上面是一样的。 好了,有了上面的基础后,我们就可以开始我们的编程之行了。 ----------------------------------------------------------------------- 二、实际应用之一:利用流制作EXE文件加密器、捆绑、自解压文件及安装程序
我们先来说一下如何制作一个EXE文件加密器吧。 EXE文件加密器的原理:建立两个文件,一个用来添加资源到另外一个EXE文件里面,称为添加程序。另外一个被添加的EXE文件称为头文件。该程序的功能是把添加到自己里面的文件读出来。Windows下的EXE文件结构比较复杂,有的程序还有校验和,当发现自己被改变后会认为自己被病毒感染而拒绝执行。所以我们把文件添加到自己的程序里面,这样就不会改变原来的文件结构了。我们先写一个添加函数,该函数的功能是把一个文件当作一个流添加到另外一个文件的尾部。函数如下:
Function Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean; var Target,Source:TFileStream; MyFileSize:integer; begin try Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareExclusive); Target:=TFileStream.Create(TargetFile,fmOpenWrite or fmShareExclusive); try Target.Seek(0,soFromEnd);//往尾部添加资源 Target.CopyFrom(Source,0); MyFileSize:=Source.Size+Sizeof(MyFileSize);//计算资源大小,并写入辅程尾部 Target.WriteBuffer(MyFileSize,sizeof(MyFileSize)); finally Target.Free; Source.Free; end; except Result:=False; Exit; end; Result:=True; end; 有了上面的基础,我们应该很容易看得懂这个函数。其中参数SourceFile是要添加的文件,参数TargetFile是被添加到的目标文件。比如说把a.exe添加到b.exe里面可以:Cjt_AddtoFile('a.exe',b.exe');如果添加成功就返回True否则返回假。 根据上面的函数我们可以写出相反的读出函数: Function Cjt_LoadFromFile(SourceFile,TargetFile :string):Boolean; var Source:TFileStream; Target:TMemoryStream; MyFileSize:integer; begin try Target:=TMemoryStream.Create; Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone); try Source.Seek(-sizeof(MyFileSize),soFromEnd); Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//读出资源大小 Source.Seek(-MyFileSize,soFromEnd);//定位到资源位置 Target.CopyFrom(Source,MyFileSize-sizeof(MyFileSize));//取出资源 Target.SaveToFile(TargetFile);//存放到文件 finally Target.Free; Source.Free; end; except Result:=false; Exit; end; Result:=true; end; 其中参数SourceFile是已经添加了文件的文件名称,参数TargetFile是取出文件后保存的目标文件名。比如说Cjt_LoadFromFile('b.exe','a.txt');在b.exe中取出文件保存为a.txt。如果取出成功就返回True否则返回假。 打开Delphi,新建一个工程,在窗口上放上一个Edit控件Edit1和两个Button:Button1和Button2。Button的Caption属性分别设置为“确定”和“取消”。在Button1的Click事件中写代码: var S:string; begin S:=ChangeFileExt(Application.ExeName,'.Cjt'); if Edit1.Text='790617' then begin Cjt_LoadFromFile(Application.ExeName,S); {取出文件保存在当前路径下并命名"原文件.Cjt"} Winexec(pchar(S),SW_Show);{运行"原文件.Cjt"} Application.Terminate;{退出程序} end else Application.MessageBox('密码不对,请重新输入!','密码错误',MB_ICONERROR+MB_OK); 编译这个程序,并把EXE文件改名为head.exe。新建一个文本文件head.rc,内容为: head exefile head.exe,然后把它们拷贝到Delphi的BIN目录下,执行Dos命令Brcc32.exe head.rc,将产生一个head.res的文件,这个文件就是我们要的资源文件,先留着。 我们的头文件已经建立了,下面我们来建立添加程序。 新建一个工程,放上以下控件:一个Edit,一个Opendialog,两个Button1的Caption属性分别设置为"选择文件"和"加密"。在源程序中添加一句:{$R head.res}并把head.res文件拷贝到程序当前目录下。这样一来就把刚才的head.exe跟程序一起编译了。 在Button1的Cilck事件里面写下代码: if OpenDialog1.Execute then Edit1.Text:=OpenDialog1.FileName; 在Button2的Cilck事件里面写下代码: var S:String; begin S:=ExtractFilePath(Edit1.Text); if ExtractRes('exefile','head',S+'head.exe') then if Cjt_AddtoFile(Edit1.Text,S+'head.exe') then if DeleteFile(Edit1.Text) then if RenameFile(S+'head.exe',Edit1.Text) then Application.MessageBox('文件加密成功!','信息',MB_ICONINFORMATION+MB_OK) else begin if FileExists(S+'head.exe') then DeleteFile(S+'head.exe'); Application.MessageBox('文件加密失败!','信息',MB_ICONINFORMATION+MB_OK) end; end; 其中ExtractRes为自定义函数,它的作用是把head.exe从资源文件中取出来。 Function ExtractRes(ResType, ResName, ResNewName : String):boolean; var Res : TResourceStream; begin try Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType)); try Res.SavetoFile(ResNewName); Result:=true; finally Res.Free; end; except Result:=false; end; end; 注意:我们上面的函数只不过是简单的把一个文件添加到另一个文件的尾部。实际应用中可以改成可以添加多个文件,只要根据实际大小和个数定义好偏移地址就可以了。比如说文件捆绑机就是把两个或者多个程序添加到一个头文件里面。那些自解压程序和安装程序的原理也是一样的,不过多了压缩而已。比如说我们可以引用一个LAH单元,把流压缩后再添加,这样文件就会变的很小。读出来时先解压就可以了。另外,文中EXE加密器的例子还有很多不完善的地方,比如说密码固定为"790617",取出EXE运行后应该等它运行完毕后删除等等,读者可以自行修改。
--------------------------------------------------------------------- 三、实际应用之二:利用流制作可执行电子贺卡
我们经常看到一些电子贺卡之类的制作软件,可以让你自己选择图片,然后它会生成一个EXE可执行文件给你。打开贺卡时就会一边放音乐一边显示出图片来。现在学了流操作之后,我们也可以做一个了。 添加图片过程我们可以直接用前面的Cjt_AddtoFile,而现在要做的是如何把图像读出并显示。我们用前面的Cjt_LoadFromFile先把图片读出来保存为文件再调入也是可以的,但是还有更简单的方法,就是直接把文件流读出来显示,有了流这个利器,一切都变的简单了。 现在的图片比较流行的是BMP格式和JPG格式。我们现在就针对这两种图片写出读取并显示函数。
Function Cjt_BmpLoad(ImgBmp:TImage;SourceFile:String):Boolean; var Source:TFileStream; MyFileSize:integer; begin Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone); try try Source.Seek(-sizeof(MyFileSize),soFromEnd); Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//读出资源 Source.Seek(-MyFileSize,soFromEnd);//定位到资源开始位置 ImgBmp.Picture.Bitmap.LoadFromStream(Source); finally Source.Free; end; except Result:=False; Exit; end; Result:=True; end; 上面是读出BMP图片的,下面的是读出JPG图片的函数,因为要用到JPG单元,所以要在程序中添加一句:uses jpeg。
Function Cjt_JpgLoad(JpgImg:Timage;SourceFile:String):Boolean; var Source:TFileStream; MyFileSize:integer; Myjpg: TJpegImage; begin try Myjpg:= TJpegImage.Create; Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone); try Source.Seek(-sizeof(MyFileSize),soFromEnd); Source.ReadBuffer(MyFileSize,sizeof(MyFileSize)); Source.Seek(-MyFileSize,soFromEnd); Myjpg.LoadFromStream(Source); JpgImg.Picture.Bitmap.Assign(Myjpg); finally Source.Free; Myjpg.free; end; except Result:=false; Exit; end; Result:=true; end; 有了这两个函数,我们就可以制作读出程序了。下面我们以BMP图片为例: 运行Delphi,新建一个工程,放上一个显示图像控件Image1。在窗口的Create事件中写上一句就可以了: Cjt_BmpLoad(Image1,Application.ExeName); 这个就是头文件了,然后我们用前面的方法生成一个head.res资源文件。 下面就可以开始制作我们的添加程序了。全部代码如下: unit Unit1;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ExtDlgs;
type TForm1 = class(TForm) Edit1: TEdit; Button1: TButton; Button2: TButton; OpenPictureDialog1: TOpenPictureDialog; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private Function ExtractRes(ResType, ResName, ResNewName : String):boolean; Function Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean; { Private declarations } public { Public declarations } end;
var Form1: TForm1;
implementation
{$R *.DFM} Function TForm1.ExtractRes(ResType, ResName, ResNewName : String):boolean; var Res : TResourceStream; begin try Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType)); try Res.SavetoFile(ResNewName); Result:=true; finally Res.Free; end; except Result:=false; end; end; Function TForm1.Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean; var Target,Source:TFileStream; MyFileSize:integer; begin try Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareExclusive); Target:=TFileStream.Create(TargetFile,fmOpenWrite or fmShareExclusive); try Target.Seek(0,soFromEnd);//往尾部添加资源 Target.CopyFrom(Source,0); MyFileSize:=Source.Size+Sizeof(MyFileSize);//计算资源大小,并写入辅程尾部 Target.WriteBuffer(MyFileSize,sizeof(MyFileSize)); finally Target.Free; Source.Free; end; except Result:=False; Exit; end; Result:=True; end; procedure TForm1.FormCreate(Sender: TObject); begin Caption:='Bmp2Exe演示程序.作者:陈经韬'; Edit1.Text:=''; OpenPictureDialog1.DefaultExt := GraphicExtension(TBitmap); OpenPictureDialog1.Filter := GraphicFilter(TBitmap);
Button1.Caption:='选择BMP图片'; Button2.Caption:='生成EXE'; end;
procedure TForm1.Button1Click(Sender: TObject); begin if OpenPictureDialog1.Execute then Edit1.Text:=OpenPictureDialog1.FileName; end;
procedure TForm1.Button2Click(Sender: TObject); var HeadTemp:String; begin if Not FileExists(Edit1.Text) then begin Application.MessageBox('BMP图片文件不存在,请重新选择!','信息',MB_ICONINFORMATION+MB_OK) Exit; end; HeadTemp:=ChangeFileExt(Edit1.Text,'.exe'); if ExtractRes('exefile','head',HeadTemp) then if Cjt_AddtoFile(Edit1.Text,HeadTemp) then Application.MessageBox('EXE文件生成成功!','信息',MB_ICONINFORMATION+MB_OK) else begin if FileExists(HeadTemp) then DeleteFile(HeadTemp); Application.MessageBox('EXE文件生成失败!','信息',MB_ICONINFORMATION+MB_OK) end; end; end. 怎么样?很神奇吧:)把程序界面弄的漂亮点,再添加一些功能,你会发现比起那些要注册的软件来也不会逊多少吧。 来自: ranjiao, 时间: 2005-08-15 19:41:40, ID: 3167931 free一调用就会出错 来自: chenybin, 时间: 2005-08-15 20:24:37, ID: 3167954 把你的代码贴出来看看 来自: ranjiao, 时间: 2005-08-15 21:03:52, ID: 3168004 begin//download <<===BUG!!! MemoryStream.Position:=0; loadfile(list.data[0],MemoryStream,msize); memo1.Lines.add('file loaded.'); socket.SendText(inttostr(msize)); end; 我在远程控制,其中涉及到的就是这几行代码了,下面是整个代码,有点多 unit server;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ScktComp, StdCtrls, ExtCtrls, Jpeg, unitserver;
type TServerForm = class(TForm) ServerSocket1: TServerSocket; BtnListen: TButton; Memo1: TMemo; BtnExit: TButton; EdtSend: TEdit; BtnSend: TButton; Timer1: TTimer; CbControl: TCheckBox; Image: TImage; BtnClear: TButton; procedure BtnClearClick(Sender: TObject); procedure Button1Click(Sender: TObject); procedure EdtSendKeyPress(Sender: TObject; var Key: Char); procedure ServerSocket1ClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure CbControlClick(Sender: TObject); procedure ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); procedure Timer1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); procedure BtnSendClick(Sender: TObject); procedure ServerSocket1Accept(Sender: TObject; Socket: TCustomWinSocket); procedure BtnListenClick(Sender: TObject); procedure BtnExitClick(Sender: TObject); private { Private declarations } public { Public declarations } end;
var ServerForm: TServerForm; control,shaking:boolean; memoryStream:TMemoryStream; size:longint; Receiving:integer; filepath:string; implementation
{$R *.dfm}
procedure capture; var BitMap:TBitMap; jpg:TJpegImage; desk:TCanvas;
begin bitmap:=tbitmap.Create; jpg:=tjpegimage.Create; desk:=tcanvas.Create; //以下代码为取得当前屏幕图象 desk.Handle:=getdc(hwnd_desktop); MemoryStream:=tmemorystream.Create; //初始化流m1,在用sendstream(m1)发送流后, with bitmap do begin width:=screen.Width; height:=screen.Height; jpg.CompressionQuality:=50; {压缩质量} jpg.Compress; canvas.CopyRect(canvas.cliprect,desk,desk.cliprect); end; jpg.Assign(bitmap); //将图象转成JPG格式 jpg.SaveToStream(MemoryStream); //将JPG图象写入流中 jpg.free; MemoryStream.Position:=0; end;
procedure TServerForm.BtnExitClick(Sender: TObject); begin close; end;
procedure TServerForm.BtnListenClick(Sender: TObject); begin ServerSocket1.active:=NOT ServerSocket1.active; if not ServerSocket1.Active then begin BtnListen.Caption:='Listen'; memo1.Lines.add('Listen ended.'); end else begin BtnListen.Caption:='End Listen'; memo1.Lines.add('Listening...'); end; end;
procedure TServerForm.ServerSocket1Accept(Sender: TObject; Socket: TCustomWinSocket); begin memo1.Lines.Add('Client from '+ServerSocket1.Socket.Connections[0].RemoteAddress+' connected.'); end;
procedure TServerForm.BtnSendClick(Sender: TObject); begin if not ServerSocket1.Socket.Connected then exit; ServerSocket1.Socket.Connections[0].SendText(EdtSend.Text); memo1.Lines.add('Server :'+EdtSend.text); end;
procedure TServerForm.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); var msize,iscmd:integer; cmd,temp:string;
//delcaration of cmdlist // maxcount=10; // CMDList:array[0..maxcount-1] of string= // ('#CLogOff', // '#CPowerOff', // '#CReboot', // '#CShakeMouse', // '#CCapture', // '#CSendStream', // '#CListDrive', // '#CListFile', // '#CDownload', // '#CUpload', // '#CExit');
procedure ReceiveStream; var len:integer; buffer:array [0..10000] of byte; begin if size=0 then begin size:=strtoint(Socket.ReceiveText); Socket.SendText('#CSendStream'); //ask client to send the stream end else begin len:=socket.ReceiveLength; //读出包长度 socket.ReceiveBuf(buffer,len); //接收数据包并读入缓冲区内 memorystream.Write(buffer,len); //追加入流M中 end; end;
begin if Receiving<>0 then // Receiving is the Flag of what socket is going to receive // 1:Stream of file that client is iploading case Receiving of 1:begin//receive stream ReceiveStream; if MemoryStream.Size>=size then begin MemoryStream.SaveToFile(list.data[0]); Receiving:=0; end; end; end else begin temp:=Socket.ReceiveText; memo1.Lines.Add('Client: '+temp); iscmd:=DealWithCMD(temp); //check if the message recevied is a command //and save the var in list. if iscmd<>0 then begin if control then begin case iscmd of 1:begin//log off //<<=====DEBUGED======>> ExitWindowsEx(EWX_Logoff,0); end; 2:begin//Power Off //<<=====DEBUGED======>> ExitWindowsEx(EWX_PowerOff,0); end; 3:begin//Reboot //<<=====DEBUGED======>> ExitWindowsEx(EWX_Reboot,0); end; 4:begin//Shake Mouse //<<=====DEBUGED======>> shaking:=not shaking; Timer1.Enabled:=true; if shaking then memo1.Lines.Add('Your mouse is going mad.') else memo1.Lines.Add('What''s wrong with your mouse?'); end; 5:begin//Capture the Screen<<=====DEBUGED======>> capture; //capture the screen and compress it into jpeg //and then save it to MemoryStream cmd:=inttostr(MemoryStream.Size); socket.SendText(cmd); end; 6:begin//Transport the Stream<<=====DEBUGED======>> MemoryStream.Position:=0; socket.SendStream(MemoryStream); end; 7:begin//List the drives.<<=====DEBUGED======>> ListDrive(cmd); socket.SendText(cmd); end; 8:begin//List the files and dirs<<=====DEBUGED======>> listFile(list.data[0],'*.*',cmd); socket.SendText(cmd); init; end; 9:begin//download <<===BUG!!! MemoryStream.Position:=0; loadfile(list.data[0],MemoryStream,msize); memo1.Lines.add('file loaded.'); socket.SendText(inttostr(msize)); end; 10:begin //upload // filepath:=list.data[0]; // socket.SendText('#CSendStream'); // receiving:=1; end; 11:begin Application.Terminate; end; 12:begin ServerForm.Show; end; end;//case end //eof if control else socket.SendText('#Server is not controlable.'); end//eof if iscmd } else begin // memo1.Lines.Add('Client: '+temp); end; end;//eof else receiving end;
procedure TServerForm.FormCreate(Sender: TObject); begin BtnListen.Click; shaking:=false; control:=true; MemoryStream:=TMemoryStream.Create; Receiving:=0; size:=0; init;//procedure in unit1; end;
procedure TServerForm.Timer1Timer(Sender: TObject); const //This procedure change the pos of mouse maxn=100; //and it make mouse like shaking... var pos:TPoint; // x,y:integer; begin if shaking then begin GetCursorPos(pos); randomize; pos.X:=pos.X+random(maxn)-(maxn div 2); pos.Y:=pos.y+random(maxn)-(maxn div 2); SetCursorPos(pos.x,pos.y); end else Timer1.enabled:=false; end;
procedure TServerForm.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin memo1.Lines.Add('Client disconected.') end;
procedure TServerForm.CbControlClick(Sender: TObject); begin if CBControl.Checked then begin control:=true; memo1.Lines.Add('You are able to be controled by client now.') end else begin control:=false; memo1.lines.add('You are not able to be controled by client now.'); end; end;
procedure TServerForm.ServerSocket1ClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin showmessage(ServerSocket1.Socket.Connections[0].RemoteHost+#13#10+'未开机或未安装服务程序'); errorcode:=0; MemoryStream.Clear; receiving:=0; end;
procedure TServerForm.EdtSendKeyPress(Sender: TObject; var Key: Char); begin if key=#13 then begin BtnSend.Click; EdtSend.Clear; end; end;
procedure TServerForm.Button1Click(Sender: TObject); begin capture; end;
procedure TServerForm.BtnClearClick(Sender: TObject); begin memo1.Clear; end;
end. 来自: chenybin, 时间: 2005-08-15 21:16:47, ID: 3168018 TMemoryStream.truncate 或者 TMemoryStream.SetSize(0);看看,明天帮你调试 来自: ranjiao, 时间: 2005-08-15 21:33:39, ID: 3168035 多谢了楼上的~
刚开始用delphibbs 怎么追加分数? 来自: chenybin, 时间: 2005-08-15 21:36:24, ID: 3168038 不用追加,追加要重新开帖子,如果答案能满足你结贴就可以了,记得发分数给偶,细细[:D][:D][:D] 来自: ranjiao, 时间: 2005-08-19 9:39:08, ID: 3172471 还是不行啊 MemoryStream没有truncate 而我用setsize的话并没有真正清内存,还是会出错 来自: chenybin, 时间: 2005-08-20 2:58:49, ID: 3173788 方便的话留个联系方式,把代码发给我,我帮你调 来自: ranjiao, 时间: 2005-08-22 22:53:12, ID: 3176438 我的邮箱是ranjiao@gmail.com 这两天快开学了,可能回的会比较慢
|