www.pudn.com > 2004021618574529928.rar > MainForm.pas
//技术讨论群组软件
//开发者:张国伟
//2004-2-7 QQ:38326155
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtCtrls, ScktComp, Menus, WinSock, Buttons,
ClipBrd, TrayBarIcon, ShellApi, ToolWin, ImgList;
type
POnlineInf=^TOnlineInf;
TOnlineInf=record //在线主机信息
UserName:String[255]; //用户标识
ControlSoc:TSocket; //客户机控制信号套接字
end;
type
TfrmMain = class(TForm)
Panel1: TPanel;
Label1: TLabel;
Panel2: TPanel;
Panel3: TPanel;
TCPData: TClientSocket;
Panel4: TPanel;
Panel5: TPanel;
Splitter1: TSplitter;
RePub: TRichEdit;
StatusBar1: TStatusBar;
MainMenu: TMainMenu;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
N5: TMenuItem;
Panel6: TPanel;
BTSpeak: TBitBtn;
Panel7: TPanel;
RETalk: TRichEdit;
Panel8: TPanel;
Panel9: TPanel;
LBOnlines: TLabel;
LBRegCount: TLabel;
Timer: TTimer;
LBFTP: TLabel;
N6: TMenuItem;
N7: TMenuItem;
PopupMenuRePub: TPopupMenu;
N8: TMenuItem;
TrayIcon: TTrayIcon;
TimerIcon: TTimer;
LBUpdate: TLabel;
N9: TMenuItem;
SaveDialog: TSaveDialog;
TimerServerMsg: TTimer;
LBServerMsg: TLabel;
FontDialog: TFontDialog;
N10: TMenuItem;
PopupMenuReTalk: TPopupMenu;
N11: TMenuItem;
N12: TMenuItem;
CBAutoScroll: TCheckBox;
CBAutoShow: TCheckBox;
LBShowSerMsg: TLabel;
ToolbarImages: TImageList;
Target: TEdit;
Panel10: TPanel;
Panel11: TPanel;
OnlineList: TListBox;
LBAllOnlines: TListBox;
Label2: TLabel;
Label3: TLabel;
LBVer: TLabel;
procedure TCPDataRead(Sender: TObject; Socket: TCustomWinSocket);
procedure TCPDataError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure N2Click(Sender: TObject);
procedure N3Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BTSpeakClick(Sender: TObject);
procedure TimerTimer(Sender: TObject);
procedure LBFTPClick(Sender: TObject);
procedure TCPDataConnecting(Sender: TObject; Socket: TCustomWinSocket);
procedure TCPDataConnect(Sender: TObject; Socket: TCustomWinSocket);
procedure TCPDataDisconnect(Sender: TObject; Socket: TCustomWinSocket);
procedure N7Click(Sender: TObject);
procedure RETalkChange(Sender: TObject);
procedure N8Click(Sender: TObject);
procedure N5Click(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure TimerIconTimer(Sender: TObject);
procedure TrayIconDblClick(Sender: TObject);
procedure LBUpdateClick(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure N9Click(Sender: TObject);
procedure RETalkKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormShow(Sender: TObject);
procedure TimerServerMsgTimer(Sender: TObject);
procedure N11Click(Sender: TObject);
procedure N12Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure WindowsFocus(Var Msg:TWMActivateApp);Message WM_ACTIVATEAPP; //用来处理 WM_ACTIVATEAPP 消息的过程
procedure LBShowSerMsgClick(Sender: TObject);
procedure OnlineListClick(Sender: TObject);
procedure LBAllOnlinesClick(Sender: TObject);
private
{ Private declarations }
Onlines:TList;
public
{ Public declarations }
end;
TOpenURL=class(TThread)
private
URL:String;
NowQuit:Boolean;
ShowMsg:String;
public
constructor Create(TempURL:String;SMsg:String;AParam:Boolean);
procedure Execute;override;
end;
var
frmMain: TfrmMain;
MYName:String;
Msg:WideString;
IsLogon:Boolean=False;
MyOpenURL:TOpenURL;
ReciveSerMsgTime:TDateTime;
implementation
uses UserReg, Login, ServerMsg, About, UnitFunction;
{$R *.dfm}
constructor TOpenURL.Create(TempURL:String;SMsg:String;AParam:Boolean);
begin
URL:=TempURL;
NowQuit:=AParam;
ShowMsg:=SMsg;
Inherited Create(False);
end;
procedure TOpenURL.Execute;
begin
FreeOnTerminate:=True;
if ShowMsg <> '' then
if Application.messagebox(PChar(ShowMsg),'执行确认',MB_YESNO + MB_DEFBUTTON2 + MB_ICONWARNING + MB_TASKMODAL)=IDNO then
Abort;
shellexecute(handle,'open',pchar(URL),nil,nil,sw_show);
if NowQuit then PostMessage(Application.Handle,WM_QUIT,0,0);
end;
procedure TfrmMain.TCPDataRead(Sender: TObject; Socket: TCustomWinSocket);
procedure ContrInfo(InBuf:array of Byte;Len:Integer); //收到控制信息
var
BasePos:Integer;
OnlineNum:Integer;
LoopNum:Integer;
LastPos:Integer;
TempStr:String;
StrLen:Integer;
TempInf:POnlineInf;
begin
OnlineList.Clear;
while (Onlines.Count > 0) do
begin
Dispose(Onlines.First);
Onlines.Delete(0);
end;
BasePos:=16;
OnlineNum:=PInteger(@InBuf[BasePos])^;
Inc(BasePos,SizeOf(Integer));
for LoopNum:= 0 to OnlineNum - 1 do
begin
LastPos:=BasePos;
while (BasePos < Len) and (InBuf[BasePos] <> 0) do Inc(BasePos);
if BasePos >= Len then Break;
if (BasePos - LastPos) > 255 then
begin
Inc(BasePos,1 + SizeOf(Integer));
Continue;
end;
TempInf:=New(POnlineInf);
StrLen:=BasePos - LastPos;
SetLength(TempStr,StrLen);
TempInf.UserName[0]:=Char(Lo(StrLen));
CopyMemory(@TempStr[1],@InBuf[LastPos],BasePos - LastPos);
CopyMemory(@TempInf.UserName[1],@InBuf[LastPos],BasePos - LastPos);
Inc(BasePos);
StrLen:=PInteger(@InBuf[BasePos])^;
TempInf.ControlSoc:=StrLen;
Inc(BasePos,SizeOf(Integer));
if OnlineList.Items.IndexOf(TempStr) = -1 then
OnlineList.Items.Add(TempStr);
Onlines.Add(TempInf);
end;
end;
procedure ServerMsg(InBuf:array of Byte;Len:Integer); //收到服务器消息
var
BasePos:Integer;
TempLen:Integer;
TempStr:String;
begin
ReciveSerMsgTime:=Now;
BasePos:=16;
TempStr:='';
Inc(BasePos,SizeOf(Integer));
while (basepos0) do inc(basepos);
TempLen:=length(TempStr);
SetLength(TempStr,TempLen+basepos-(16 + sizeof(integer)));
copymemory(@TempStr[TempLen+1],@inbuf[16 + sizeof(integer)],basepos-(16 + sizeof(integer)));
Msg:=Copy(TempStr,TempLen + 1,(LengTh(TempStr) - TempLen));
TimerServerMsg.Enabled:=True;
end;
procedure TalkInfo(InBuf:array of Byte;Len:Integer); //收到群组发言信息
var
BasePos:Integer;
TempStr:String;
SoureName,TargeName:String;
TempLen:Integer;
SIDNum,TIDNum:Integer;
I:Integer;
begin
BasePos:=16;
SIDNum:=Pinteger(@InBuf[BasePos])^; //取得发信息者 Socket 句柄
TempStr:='';
for I:=0 to Onlines.Count-1 do //取得发信息者名称
if (POnlineinf(Onlines.Items[I]).ControlSoc = SIDNum) then
begin
SoureName:= POnlineinf(Onlines.Items[I]).UserName;
Break;
end;
Inc(BasePos,SizeOf(Integer));
TIDNum:=Pinteger(@InBuf[BasePos])^; //取得收信息者 Socket 句柄
for I:=0 to Onlines.Count-1 do //取得收信息者名称
if (POnlineinf(Onlines.Items[I]).ControlSoc = TIDNum) then
begin
TargeName:= POnlineinf(Onlines.Items[I]).UserName;
Break;
end;
Inc(BasePos,SizeOf(Integer));
if SoureName='' then TempStr:='某位不知名的聊天者 (已经下线) ';
if TargeName='' then TargeName:='大家';
TempStr:=SoureName + ' 对 ' + TargeName + ' 说: ' +' (' + DateTimeToStr(Now) + ')';
if TargeName = SoureName then TempStr:=SoureName + ' 因连续玩 Delphi 过久,正自言自语: ' +' (' + DateTimeToStr(Now) + ')';
RePub.SelAttributes.Color:=clBlue;
RePub.Lines.Add(TempStr);
while (BasePos < Len) and (InBuf[BasePos] <> 0) do Inc(BasePos);
TempLen:=LengTh(TempStr);
SetLength(TempStr,TempLen+BasePos-(16 + SizeOf(Integer)));
CopymeMory(@TempStr[TempLen+1],@InBuf[16 + SizeOf(Integer)*2],BasePos-(16 + sizeof(integer)*2));
try
RePub.SelAttributes.Color:=clBlack;
RePub.Lines.Add(Copy(TempStr,TempLen + 1,BasePos-(16 + sizeof(integer)*2)));
if CBAutoShow.Checked then
begin
TrayIcon.ShowMainForm;
SetForegroundWindow(frmMain.Handle);
RETalk.SetFocus;
end;
if CBAutoScroll.Checked then
begin
RePub.Perform(EM_ScrollCaret,0,0);
end;
except
On Exception do
end;
if not frmMain.Active then TimerIcon.Enabled:=True;
end;
var
Buf:array of Byte;
Data:WideString;
Len:Integer;
I:Integer;
IsContrInfo:Boolean;
IsTalkInfo:Boolean;
IsServerMsgInfo:Boolean;
begin
Len:=Socket.ReceiveLength;
SetLength(Buf,Len);
Socket.ReceiveBuf(Buf[0],Len);
Data:=String(Buf);
if pos('$Z$CanReg',Data)=1 then
begin
ShowMessage('可以注册!');
frmReg.EDUserName.Enabled:=True;
frmReg.EDPwd.Enabled:=True;
frmReg.EDPwd2.Enabled:=True;
frmReg.EDEmail.Enabled:=True;
frmReg.Button1.Enabled:=True;
frmReg.Button2.Enabled:=True;
frmReg.EDPwd.SetFocus;
end;
if pos('$Z$NoReg',Data)=1 then
begin
ShowMessage('用户名已经被占用!');
frmReg.EDUserName.Enabled:=True;
frmReg.EDPwd.Enabled:=True;
frmReg.EDPwd2.Enabled:=True;
frmReg.EDEmail.Enabled:=True;
frmReg.Button1.Enabled:=True;
frmReg.Button2.Enabled:=True;
frmReg.EDUserName.Text:='';
frmReg.EDUserName.SetFocus;
end;
if pos('$Z$CompleteReg',Data)=1 then
begin
ShowMessage('注册成功,请登录!');
frmReg.Close;
end;
if pos('$Z$NoUser',Data)=1 then
begin
ShowMessage('无此用户!');
frmLogin.EDUserName.Enabled:=True;
frmLogin.EDPwd.Enabled:=True;
frmLogin.Button1.Enabled:=True;
frmLogin.EDUserName.Text:='';
frmLogin.EDUserName.SetFocus;
end;
if pos('$Z$NoPwd',Data)=1 then
begin
ShowMessage('密码错误!');
frmLogin.EDUserName.Enabled:=True;
frmLogin.EDPwd.Enabled:=True;
frmLogin.Button1.Enabled:=True;
frmLogin.EDPwd.Text:='';
frmLogin.EDPwd.SetFocus;
end;
if pos('$Z$LoginOk',Data)=1 then
begin
frmLogin.Close;
IsLogon:=True;
RETalk.SetFocus;
Socket.SendText('$Z$OneCount');
end;
if pos('$Z$Logon',Data)=1 then
begin
ShowMessage('此用户已经登录');
Exit;
end;
if pos('$Z$AllCount',Data)=1 then
begin
LBRegCount.Caption:=Format('注册用户 %s 人',[Copy(Data,12,9)]);
end;
if pos('$Z$OneCount',Data)=1 then
begin
LBRegCount.Caption:=Format('注册用户 %s 人',[Copy(Data,12,9)]);
Socket.SendText('$Z$GetServerMsg');
end;
IsContrInfo:=True;
for I:= 0 to 16 - 1 do
begin
if ((I mod 2) = 0) then IsContrInfo:=IsContrInfo and (Buf[I]=$A)
else IsContrInfo:=IsContrInfo and (Buf[I]=$F);
if not IsContrInfo then Break;
end;
if IsContrInfo then ContrInfo(Buf,Len);
IsTalkInfo:=True;
for I:= 0 to 16 - 1 do
begin
if ((I mod 2) = 0) then IsTalkInfo:=IsTalkInfo and (Buf[I]=$F)
else IsTalkInfo:=IsTalkInfo and (Buf[I]=$A);
if not IsTalkInfo then Break;
end;
if IsTalkInfo then TalkInfo(Buf,Len);
IsServerMsgInfo:=True;
for I:= 0 to 16 - 1 do
begin
if ((I mod 2) = 0) then IsServerMsgInfo:=IsServerMsgInfo and (Buf[I]=$C)
else IsServerMsgInfo:=IsServerMsgInfo and (Buf[I]=$A);
if not IsServerMsgInfo then Break;
end;
if IsServerMsgInfo then ServerMsg(Buf,Len);
end;
procedure TfrmMain.TCPDataError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
StatusBar1.Panels[0].Text:='出现连接错误!';
ErrorCode:=0;
end;
procedure TfrmMain.N2Click(Sender: TObject);
begin
frmReg:=TfrmReg.Create(Self);
frmReg.ShowModal;
end;
procedure TfrmMain.N3Click(Sender: TObject);
begin
frmLogin:=TfrmLogin.Create(Self);
frmLogin.ShowModal;
end;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
Onlines:=TList.Create;
TrayIcon.Icon:=Application.Icon;
end;
procedure TfrmMain.BTSpeakClick(Sender: TObject);
var
Buf:array of Byte;
TempStr:String;
I:Integer;
UserID:Integer;
begin
if MYName = '' then
begin
ShowMessage('请登录!');
Exit;
end;
if not TCPData.Active then exit;
if RETalk.Lines.Count > 300 then
begin
ShowMessage('字数太多,将在300行处截断,然后发送!');
BTSpeak.Enabled:=False;
end;
if RETalk.Lines.Count = 0 then
begin
ShowMessage('不能发空信息!');
Exit;
end;
Target.Text:=Trim(Target.Text);
UserID:=-1;
for i:=0 to Onlines.Count-1 do
if Target.Text=POnlineinf(Onlines.Items[i]).UserName then
begin
UserID:=POnlineinf(Onlines.Items[i]).ControlSoc;
Break;
end;
if UserID=-1 then UserID:=0;
TempStr:=Trim(RETalk.Text);
Setlength(Buf,16 + SizeOf(Integer)+Length(TempStr)+1);
for i:=0 to 16 - 1 do
if ((i mod 2)=0 ) then buf[i]:=$F
else buf[i]:=$A;
Pinteger(@Buf[16])^:=UserID;
CopyMemory(@Buf[16 + SizeOf(Integer)],@TempStr[1],Length(TempStr));
Buf[length(buf)-1]:=0;
TCPData.Socket.SendBuf(buf[0],length(buf));
RETalk.Clear;
RETalk.SetFocus;
keybd_event( VK_BACK, MapVirtualKey( VK_BACK, 0 ), 0 , 0 ); // BACK down
keybd_event( VK_BACK, MapVirtualKey( VK_BACK, 0 ), KEYEVENTF_KEYUP , 0 ); // BACK key up
end;
procedure TfrmMain.TimerTimer(Sender: TObject);
begin
LBOnlines.Caption:=Format('当前在线 %s 人',[IntToStr(OnlineList.Count)]);
end;
procedure TfrmMain.LBFTPClick(Sender: TObject);
begin
frmAbout:=TfrmAbout.Create(Self);
frmAbout.Show;
end;
procedure TfrmMain.TCPDataConnecting(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.Panels[0].Text:='正在连接服务器...';
end;
procedure TfrmMain.TCPDataConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.Panels[0].Text:='已经连接到服务器';
frmLogin:=TfrmLogin.Create(Self);
frmLogin.ShowModal;
end;
procedure TfrmMain.TCPDataDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.Panels[0].Text:='连接已经断开!';
end;
procedure TfrmMain.N7Click(Sender: TObject);
begin
TCPData.Active:=False;
TCPData.Active:=True;
end;
procedure TfrmMain.RETalkChange(Sender: TObject);
begin
if RETalk.Lines.Count < 300 then
BTSpeak.Enabled:=True;
end;
procedure TfrmMain.N8Click(Sender: TObject);
begin
RePub.CopyToClipboard;
end;
procedure TfrmMain.N5Click(Sender: TObject);
begin
if Application.messagebox('您要关闭吗?','执行确认',MB_YESNO + MB_DEFBUTTON2 + MB_ICONWARNING + MB_TASKMODAL)=IDNO then
Abort
else
begin
if IsLogon then TCPData.Socket.SendText('$Z$Out' + MYName);
Onlines.Free;
TCPData.Active:=False;
end;
end;
procedure TfrmMain.FormResize(Sender: TObject);
begin
BTSpeak.Left:=Panel6.Width - 100;
end;
procedure TfrmMain.TimerIconTimer(Sender: TObject);
begin
if TrayIcon.Icon.Empty then TrayIcon.Icon:=Application.Icon
else
TrayIcon.Icon:=Nil;
end;
procedure TfrmMain.TrayIconDblClick(Sender: TObject);
begin
TrayIcon.ShowMainForm;
SetForegroundWindow(frmMain.Handle);
TimerIcon.Enabled:=False;
TrayIcon.Icon:=Application.Icon;
end;
procedure TfrmMain.LBUpdateClick(Sender: TObject);
begin
MyOpenURL:=TOpenURL.Create('ftp://61.187.64.68/Client.exe','确认后将自动关闭当前的群组程序,确认吗?',True);
end;
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if Application.messagebox('您要关闭吗?','执行确认',MB_YESNO + MB_DEFBUTTON2 + MB_ICONWARNING + MB_TASKMODAL)=IDNO then
Abort
else
begin
if IsLogon then TCPData.Socket.SendText('$Z$Out' + MYName);
Onlines.Free;
TCPData.Active:=False;
end;
end;
procedure TfrmMain.N9Click(Sender: TObject);
begin
if SaveDialog.Execute then
begin
RePub.Lines.SaveToFile(SaveDialog.FileName+'.Rtf');
end;
end;
procedure TfrmMain.RETalkKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (ssCtrl in Shift) and (Key = 13) then
begin
BTSpeak.Click;
RETalk.Clear;
end;
end;
procedure TfrmMain.FormShow(Sender: TObject);
begin
TCPData.Open;
end;
procedure TfrmMain.TimerServerMsgTimer(Sender: TObject);
begin
LBServerMsg.Visible:=not LBServerMsg.Visible;
end;
procedure TfrmMain.N11Click(Sender: TObject);
begin
RETalk.CopyToClipboard;
end;
procedure TfrmMain.N12Click(Sender: TObject);
begin
RETalk.PasteFromClipboard;
end;
procedure TfrmMain.Button1Click(Sender: TObject);
begin
RePub.SetFocus;
end;
procedure TfrmMain.WindowsFocus(var Msg:TWMActivateApp);
begin
TimerIcon.Enabled:=False;
TrayIcon.Icon:=Application.Icon;
inherited;
end;
procedure TfrmMain.LBShowSerMsgClick(Sender: TObject);
begin
LBServerMsg.Visible:=True;
if not Assigned(frmServerMsg) then frmServerMsg:=TfrmServerMsg.Create(Self);
frmServerMsg.Show;
if (ReciveSerMsgTime <> 0) and (TimerServerMsg.Enabled) then
begin
frmServerMsg.MOServerMsg.SelAttributes.Color:=clBlue;
frmServerMsg.MOServerMsg.Lines.Add('收到时间: ' + DateTimeToStr(ReciveSerMsgTime));
frmServerMsg.MOServerMsg.SelAttributes.Color:=clBlack;
frmServerMsg.MOServerMsg.Lines.Add(Msg);
frmServerMsg.MOServerMsg.Lines.Add('');
frmServerMsg.MOServerMsg.Perform(EM_ScrollCaret,0,0);
TimerServerMsg.Enabled:=False;
end;
end;
{function TfrmMain.CurrText: TTextAttributes;
begin
if RETalk.SelLength > 0 then Result := RETalk.SelAttributes
else Result := RETalk.DefAttributes;
end;}
{procedure TfrmMain.FontNameChange(Sender: TObject);
begin
if FUpdating then Exit;
CurrText.Name := FontName.Items[FontName.ItemIndex];
end; }
procedure TfrmMain.OnlineListClick(Sender: TObject);
begin
if onlinelist.SelCount<>0 then
begin
Target.Text:=OnlineList.Items[OnlineList.ItemIndex];
RETalk.SetFocus;
end;
end;
procedure TfrmMain.LBAllOnlinesClick(Sender: TObject);
begin
Target.Text:='全部在线 D 友';
end;
end.