zoukankan      html  css  js  c++  java
  • Indy10 即时通讯Demo

    最近闲来无事,重新学习了Indy10,顺手写了一段即时通讯代码。与上次写的笔记有不同之处,但差别不大。

    未研究过TCP打洞技术,所以下面的代码采用的是  客户端--服务器--客户端  模式,也就是服务器端转发消息的模式。

     客户端模仿了QQ,可以在屏幕四周停靠自动隐藏

    本文也演示了在线程中操作VCL的两张方法:

    1:向主线程发送消息

    2:在线程中使用临界区

    program Server;
    
    uses
      Forms,
      UntMain in 'UntMain.pas' {Form2},
      Unit2 in 'Unit2.pas',
      Unit4 in 'Unit4.pas';
    
    {$R *.res}
    
    begin
      Application.Initialize;
      Application.MainFormOnTaskbar := True;
      Application.CreateForm(TForm2, Form2);
      Application.Run;
    end.
    

    服务器端:

    unit UntMain;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, IdContext, IdScheduler, IdSchedulerOfThread, IdSchedulerOfThreadPool,
      IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, ImgList,
      CoolTrayIcon, ExtCtrls, RzPanel, Unit2, IdGlobal, StdCtrls, RzLstBox,
      IdSchedulerOfThreadDefault, RzStatus, RzButton, RzEdit,SyncObjs;
    
    type
      TForm2 = class(TForm)
        CoolTrayIcon1: TCoolTrayIcon;
        ImageList1: TImageList;
        IdTCPServer1: TIdTCPServer;
        RzStatusBar1: TRzStatusBar;
        RzListBox1: TRzListBox;
        IdSchedulerOfThreadDefault1: TIdSchedulerOfThreadDefault;
        Button1: TButton;
        RzStatusPane1: TRzStatusPane;
        RzStatusPane2: TRzStatusPane;
        RzMemo1: TRzMemo;
        RzButton1: TRzButton;
        RzMemo2: TRzMemo;
        Timer1: TTimer;
        procedure IdTCPServer1Execute(AContext: TIdContext);
        procedure CustomMessage(var message: TMessage); message CustMsg;
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure Button1Click(Sender: TObject);
        procedure IdTCPServer1Disconnect(AContext: TIdContext);
        procedure RzButton1Click(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
      private
        { Private declarations }
    
      public
        { Public declarations }
      end;
      //TIdServerContext 类继承自 TIdContext类
      //IdCustomTCPServer 单元 第295行
      TMyClass = class(TIdServerContext)
        CltInfo: TCltInfo;
      end;
    
    var
      Form2: TForm2;
      CriticalSection:TCriticalSection;
    implementation
    
    {$R *.dfm}
    uses
      Unit4;
    procedure TForm2.Button1Click(Sender: TObject);
    begin
      IdTCPServer1.Active := True;
      if IdTCPServer1.Active then
      begin
        RzMemo1.Lines.Add('服务器开启成功...');
      end;
    end;
    
    procedure TForm2.CustomMessage(var message: TMessage);
    var
      i,n: Integer;
      ss,ip,Nc,sNc: string;
      buf:TDataPack;
      list:Tlist;
      FContext:TIdContext;
    begin
      FContext := TMyClass(message.LParam);
      case message.WParam of
        CltConnect:
        begin
          ss:='';
          Nc := TMyClass(FContext).CltInfo.CltName;
          ip:= TMyClass(FContext).CltInfo.CltIP;
          RzListBox1.Items.Add(Nc);
          RzMemo2.Lines.Add('【客户:】' + Nc + ' (' + ip +') 登陆'+'---'+DateTimeToStr(Now));
    
          for i := 0 to RzListBox1.Items.Count - 1 do // 发送连线客户端列表
            ss:=ss+form2.RzListBox1.ItemCaption(i)+'|';
          sNc :=Encrystrings(ss);
          FillChar(buf, SizeOf(TDataPack), '');
          buf.Command := CltList;
          StrCopy(@buf.Data, PChar(sNc));
          List := form2.IdTCPServer1.Contexts.LockList;
          n:= List.Count;
          try
            for I := 0 to n-1 do
            begin
              try
    
                TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
              except
                //
              end;
            end;
          finally
            form2.IdTCPServer1.Contexts.UnlockList;
          end;
        end;
    
        CltDisconnect:
          begin
            for i := 0 to RzListBox1.Items.Count - 1 do
            begin
              if RzListBox1.ItemCaption(i) = TMyClass(FContext).CltInfo.CltName  then
              begin
    
                RzListBox1.Items.Delete(i);
                RzMemo2.Lines.Add('【用户:】 '+ string(TMyClass(FContext).CltInfo.CltName) +'  离开---'+DateTimeToStr(Now));
                Break;
              end;
            end;
    
            FillChar(buf, SizeOf(TDataPack), '');
            ss := '';
    
            for i := 0 to RzListBox1.Items.Count - 1 do // 发送连线客户端列表
              ss := ss + Form2.RzListBox1.ItemCaption(i) + '|';
            ss:=Encrystrings(ss);
            buf.Command := CltList;
            StrCopy(@buf.Data, PChar(ss));
            list:= IdTCPServer1.Contexts.LockList;
            n:= List.Count;
            try
              for i := 0 to n - 1 do
              try
                TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
              except
                //
              end;
            finally
              IdTCPServer1.Contexts.UnlockList;
            end;
          end;
        CltSendMessage:
          begin
    
          end;
      end;
    end;
    
    procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
    
      RzListBox1.Clear;
      IdTCPServer1.Active := False;
    end;
    
    procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    var
      List:TList;
      i,n:Integer;
      LContext: TMyClass;
      buf:TDataPack;
    begin
      //当有客户端尚未断开连接时,服务器主动断开连接会导致异常
      //所以,在服务器端退出之前,检查时候有客户端尚未断开
      //若有,通知客户端主动断开连接
      List:= IdTCPServer1.Contexts.LockList;
      n:= List.Count;
      try
        if n >0 then
        begin
          CanClose := False;
          FillChar(buf,SizeOf(TdataPack),'');
          buf.Command := SrvCloseQuery;
          for I := 0 to n - 1 do
          begin
            LContext := TMyClass(List.Items[i]);
            LContext.Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
          end;
        end else CanClose := True;
      finally
        IdTCPServer1.Contexts.UnlockList;
      end;
    end;
    
    procedure TForm2.FormCreate(Sender: TObject);
    begin
      //在IdCustomTCPServer 单元第302行,定义了类的指针:
      //TIdServerContextClass = class of TIdServerContext;
      //AContext不确定以 TIdServerContext类创建,所以定义了一个类的指针TIdServerContextClass,
      //AContext将以TIdServerContextClass指针所指向的类来创建,重新赋值指针,将以新类创建实例
    
      //这里重新赋值AContext 新类,当客户端连接后,AContext将以新类TMyClass的实例创捷
      //AContext 被创建后,将包含TMyClass类的新属性 TCltInfo
      //详见IdCustomTCPServer 单元第956行
      //如果不重新赋值AContext新类,AContext 在IdCustomTCPServer初始化时(TIdCustomTCPServer.InitComponent方法),
      //以默认类TIdServerContext创建
      //详见 IdCustomTCPServer 单元第812行
      //这里我们需要给AContext 添加新属性 TCltInfo 用来保存客户端信息
      //所以,以TIdServerContext 为基类,我们扩展出  TMyClass 子类
      //每个客户端连接后,AContext即被创建,并把每个AContext地址(对象指针)保存在IdTCPServer.Contexts属性中
      //当服务器端需要与某个客户端回话时,可以遍历Contexts属性
      IdTCPServer1.ContextClass := TMyClass;
      IdTCPServer1.Active := True;
      if IdTCPServer1.Active then
      begin
        RzMemo1.Lines.Add('服务器开启成功...('+ DateTimeToStr(Now) + ')');
      end;
      CriticalSection:=TCriticalSection.Create;
    end;
    
    procedure TForm2.FormDestroy(Sender: TObject);
    begin
      CriticalSection.Free;
    end;
    
    procedure TForm2.IdTCPServer1Disconnect(AContext: TIdContext);
    begin
      SendMessage(Handle,CustMsg,CltDisconnect,LongInt(AContext));
    end;
    
    procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
    var
      BByte: TIdBytes;
      buf: TDataPack;
      i,n: Integer;
      s,ss,ds,nr,Nc,ip:string;
      List:Tlist;
    begin
      FillChar(buf, SizeOf(TDataPack), '');
      AContext.Connection.IOHandler.ReadBytes(BByte, SizeOf(TDataPack), False);
      BytesToRaw(BByte, buf, SizeOf(TDataPack));
    //---------------------------------------------------------------------------------------
      case buf.Command of
        CltConnect:
          begin
            ss:='';
            s:= string(buf.CltInfo.CltName);
            Nc :=Uncrystrings(s);
            ip:=AContext.Binding.PeerIP;
            StrCopy(@TMyClass(AContext).CltInfo.CltName,PChar(Nc)) ;
            StrCopy(@TMyClass(AContext).CltInfo.CltIP,PChar(ip));
            Nc :=Uncrystrings(s);
            for i := 0 to RzListBox1.Items.Count - 1 do
            begin
              if RzListBox1.Items[i]=Nc then
              begin
                buf.Command := CltDisconnect;
                AContext.Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
                Exit;
              end;
            end;
            SendMessage(Handle,CustMsg,CltConnect,LongInt(AContext));
          end;
    //------------------------------------------------------------------------------------------------
        CltSendMessage:
          begin
            s:= Uncrystrings(string(buf.CltInfo.CltName));
            ds:=Uncrystrings(string(buf.DstInfo.CltName));
            nr:=Uncrystrings(string(buf.Data)) +#13+#10;
            List := form2.IdTCPServer1.Contexts.LockList;
            n:= List.Count;
            try
              for i := 0 to n - 1 do
              begin
                if TMyClass(List.Items[i]).CltInfo.CltName = ds then
                begin
                  try
                    CriticalSection.Enter;
                    try
                      TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
                      RzMemo1.Lines.Add(s + '对 '+ds + ' 说:'+ nr);
                    finally
                      CriticalSection.Leave;
                    end;
                  except
                    buf.Command := SrvMessage;
                    AContext.Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
                  end;
                  Exit;
                end;
              end;
            finally
              form2.IdTCPServer1.Contexts.UnlockList;
            end;
          end;
    //--------------------------------------------------------------------------------------------------------
        CltTimer :
        begin
          AContext.Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
        end;
    //---------------------------------------------------------------------------------------------------------
        CltClear :
        begin
          s:= Uncrystrings(string(buf.CltInfo.CltName));
          ds:=Uncrystrings(string(buf.DstInfo.CltName));
          List := form2.IdTCPServer1.Contexts.LockList;
          n:= List.Count;
          try
            for i := 0 to n - 1 do
            begin
              if TMyClass(List.Items[i]).CltInfo.CltName = ds then
              begin
                try
                  CriticalSection.Enter;
                  try
                    TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
                    RzMemo1.Lines.Add(s + ' 清除了 '+ds + ' 的屏幕'+#13+#10);
                  finally
                    CriticalSection.Leave;
                  end;
                except
                  //
                end;
                Exit;
              end;
            end;
          finally
            form2.IdTCPServer1.Contexts.UnlockList;
          end;
        end;
    //-------------------------------------------------------------------------------------------------------
        CltLockSrc:
        begin
          s:= Uncrystrings(string(buf.CltInfo.CltName));
          List := form2.IdTCPServer1.Contexts.LockList;
          n:= List.Count;
          try
            for i := 0 to n - 1 do
            begin
              if TMyClass(List.Items[i]).CltInfo.CltName <> s then
              begin
                try
                  CriticalSection.Enter;
                  try
                    TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
                  finally
                    CriticalSection.Leave;
                  end;
                except
                  //
                end;
              end;
            end;
          finally
            form2.IdTCPServer1.Contexts.UnlockList;
          end;
          RzMemo1.Lines.Add(s + ' 锁定了屏幕 '+#13+#10);
        end;
    //-------------------------------------------------------------------------------------------------------
        CltUnlockSrc :
        begin
          s:= Uncrystrings(string(buf.CltInfo.CltName));
          List := form2.IdTCPServer1.Contexts.LockList;
          n:= List.Count;
          try
            for i := 0 to n - 1 do
            begin
              if TMyClass(List.Items[i]).CltInfo.CltName <> s then
              begin
                try
                  TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
    
                except
                  //
                end;
              end;
            end;
          finally
            form2.IdTCPServer1.Contexts.UnlockList;
          end;
          RzMemo1.Lines.Add(s + ' 解锁了屏幕 '+#13+#10);
        end;
    //---------------------------------------------------------------------------------------------------------------
        CltMessage :
        begin
          ds:=Uncrystrings(string(buf.DstInfo.CltName));
          List := form2.IdTCPServer1.Contexts.LockList;
          n:= List.Count;
          try
          for i := 0 to n - 1 do
          begin
            if TMyClass(List.Items[i]).CltInfo.CltName = ds then
            begin
              try
                TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
              except
                //
              end;
              Exit;
            end;
          end;
          finally
            form2.IdTCPServer1.Contexts.UnlockList;
          end;
        end;
    //-----------------------------------------------------------------------------------------------------------------
      end;
    end;
    
    procedure TForm2.RzButton1Click(Sender: TObject);
    begin
      RzMemo1.Clear;
    end;
    
    end.
    

      客户端

    program Project3;
    
    uses
      Forms,
      windows,
      Unit3 in 'Unit3.pas' {Form3},
      Unit1 in 'Unit1.pas' {Form1},
      Unit2 in 'Unit2.pas',
      Unit4 in 'Unit4.pas';
    
    {$R *.res}
    
    begin
      Application.Initialize;
      Application.MainFormOnTaskbar := False ;
      Application.CreateForm(TForm3, Form3);
      SetWindowLong(Application.Handle,GWL_EXSTYLE,WS_EX_TOOLWINDOW);
    
      Application.Run;
    end.
    

      

    unit Unit3;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, RzLstBox, ExtCtrls, ShellAPI, ImgList, RzTray, IdGlobal,
      Unit2,Clipbrd,
      IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, RzButton,
      RzRadChk, RzPanel, Mask, RzEdit, RzLabel, ComCtrls, Menus, RzBHints, RzSplit,
      RzAnimtr, IdZLibCompressorBase, IdCompressorZLib,RxRichEd, RzListVw,Buttons,
      RzSpnEdt ;
    
    type
      TForm3 = class(TForm)
        RzListBox1: TRzListBox;
        Timer1: TTimer;
        RzTrayIcon1: TRzTrayIcon;
        ImageList1: TImageList;
        IdTCPClient1: TIdTCPClient;
        RzCheckBox1: TRzCheckBox;
        RzPanel1: TRzPanel;
        RzPanel2: TRzPanel;
        RzMemo2: TRzMemo;
        RzLabel1: TRzLabel;
        RzEdit1: TRzEdit;
        RzButton2: TRzButton;
        RzLabel2: TRzLabel;
        RzEdit2: TRzEdit;
        Timer2: TTimer;
        PopupMenu1: TPopupMenu;
        N1: TMenuItem;
        RzButton3: TRzButton;
        BalloonHint1: TBalloonHint;
        RzLabel5: TRzLabel;
        RzEdit3: TRzEdit;
        RzSplitter1: TRzSplitter;
        RzSplitter2: TRzSplitter;
        RzAnimator1: TRzAnimator;
        ImageList2: TImageList;
        RzToolButton1: TRzToolButton;
        PopupMenu2: TPopupMenu;
        N2: TMenuItem;
        N3: TMenuItem;
        N4: TMenuItem;
        ImageList3: TImageList;
        RzButton4: TRzButton;
        RzButton5: TRzButton;
        RxRichEdit1: TRxRichEdit;
        LabeledEdit1: TLabeledEdit;
        RzPanel3: TRzPanel;
        Image01: TImage;
        Image02: TImage;
        Image03: TImage;
        Image04: TImage;
        Image05: TImage;
        Image06: TImage;
        Image07: TImage;
        Image08: TImage;
        Image09: TImage;
        Image10: TImage;
        Image11: TImage;
        Image12: TImage;
        Image13: TImage;
        Image14: TImage;
        Image15: TImage;
        Image16: TImage;
        Image17: TImage;
        Image18: TImage;
        Image19: TImage;
        Image20: TImage;
        Image21: TImage;
        Image22: TImage;
        Image23: TImage;
        Image24: TImage;
        Image25: TImage;
        Image26: TImage;
        Image27: TImage;
        Image28: TImage;
        Image29: TImage;
        Image30: TImage;
        Image31: TImage;
        Image32: TImage;
        Image33: TImage;
        Image34: TImage;
        Image35: TImage;
        Image36: TImage;
        Image37: TImage;
        Image38: TImage;
        Image39: TImage;
        Image40: TImage;
        Image41: TImage;
        Image42: TImage;
        Image43: TImage;
        Image44: TImage;
        Button1: TButton;
        RzButton1: TRzButton;
        ScrollBox1: TScrollBox;
        Image1: TImage;
        Image45: TImage;
        Image46: TImage;
        Image47: TImage;
        Image48: TImage;
        Image49: TImage;
        Image50: TImage;
        Image51: TImage;
        Timer3: TTimer;
        Image2: TImage;
        FontDialog1: TFontDialog;
        procedure FormCreate(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
        procedure WMMOVING(var Msg: TMessage); message WM_MOVING;
        procedure wmsizing(var Msg: TMessage); message WM_SIZING;
        procedure RevCustMsg(var Msg:TMessage);message CustMsg;
        procedure SetBarHeight;
        procedure RzListBox1DblClick(Sender: TObject);
        procedure RzCheckBox1Click(Sender: TObject);
        procedure IdTCPClient1Connected(Sender: TObject);
        procedure IdTCPClient1Disconnected(Sender: TObject);
        procedure RzButton1Click(Sender: TObject);
        procedure RzButton2Click(Sender: TObject);
        procedure RzMemo2KeyPress(Sender: TObject; var Key: Char);
        procedure Timer2Timer(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure RzTrayIcon1RestoreApp(Sender: TObject);
        procedure RzTrayIcon1MinimizeApp(Sender: TObject);
        procedure RzMemo2MouseEnter(Sender: TObject);
        procedure FormMouseEnter(Sender: TObject);
        function MousePosion:Boolean;
        procedure RzListBox1MouseEnter(Sender: TObject);
        procedure N1Click(Sender: TObject);
        procedure RzButton3Click(Sender: TObject);
        procedure LabeledEdit1KeyPress(Sender: TObject; var Key: Char);
        procedure RzEdit3KeyPress(Sender: TObject; var Key: Char);
        procedure RzEdit1KeyPress(Sender: TObject; var Key: Char);
        procedure PopupMenu1Popup(Sender: TObject);
        procedure N4Click(Sender: TObject);
        procedure RzButton4Click(Sender: TObject);
        procedure RzButton5Click(Sender: TObject);
        procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
        procedure RxRichEdit1MouseMove(Sender: TObject; Shift: TShiftState; X,
          Y: Integer);
        procedure Image01Click(Sender: TObject);
        procedure RzSpinButtons1DownLeftClick(Sender: TObject);
        procedure RzSpinButtons1UpRightClick(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure RxRichEdit1URLClick(Sender: TObject; const URLText: string;
          Button: TMouseButton);
        procedure Image1Click(Sender: TObject);
        function  MouseInScrollBox:Boolean;
        procedure Timer3Timer(Sender: TObject);
        procedure Image2Click(Sender: TObject);
      private
        { Private declarations }
        FAnchors: TAnchors;
      public
        { Public declarations }
      end;
    
      TRevDataThread = class(TThread)
      private
        buf: TDataPack;
      protected
        procedure Execute; override;
        procedure ShowMsg;
        procedure AddCltList;
        procedure DoDiscnt;
        procedure ClearScr;
        procedure AddMessage;
        procedure CltMessageIn;
        procedure DoSrvMessage;
        procedure DoSrvCloseQuery;
      end;
      // HidePosKind = (hpTop, hpLeft, hpBottom, hpRight);
      // THidePos = set of HidePosKind;
    
    var
      Form3: TForm3;
      Lst_Height: Integer; // 记录窗体隐藏前的高度
      Lst_Width: Integer; // 记录窗体隐藏前的宽度
      Rec_Position: Boolean; // 是否启动窗体宽高记录标志
      Cur_Top, Cur_Bottom: Integer; // 隐藏后窗体的顶端和底部位置
      RevDataThread:TRevDataThread;
      BoolEnable:Boolean;
    implementation
    
    uses Math, types, Unit1,StrUtils,Unit4;
    {$R *.dfm}
    
    procedure TForm3.WMMOVING(var Msg: TMessage);
    begin
      inherited;
      with PRect(Msg.LParam)^ do
      begin
        if (akLeft in FAnchors) or (akRight in FAnchors) then
        begin
          if (Left > 0) and (Right < Screen.Width) then
          begin
            if Rec_Position then
            begin
              Bottom := top + Lst_Height;
              Right := Left + Lst_Width;
              Height := Lst_Height;
              Width := Lst_Width;
            end;
          end
          else
          begin
            SetBarHeight;
            top := Cur_Top;
            Bottom := Cur_Bottom;
            exit;
          end;
        end;
        Left := Min(Max(0, Left), Screen.Width - Width);
        top := Min(Max(0, top), Screen.Height - Height);
        Right := Min(Max(Width, Right), Screen.Width);
        Bottom := Min(Max(Height, Bottom), Screen.Height);
        if not Rec_Position then
        begin
          Lst_Height := Form3.Height;
          Lst_Width := Form3.Width;
        end;
        FAnchors := [];
        if Left = 0 then
          Include(FAnchors, akLeft);
        if Right = Screen.Width then
          Include(FAnchors, akRight);
        if top = 0 then
          Include(FAnchors, akTop);
        if Bottom = Screen.Height then
          Include(FAnchors, akBottom);
        Timer1.Enabled := FAnchors <> [];
        if (akLeft in FAnchors) or (akRight in FAnchors) then
        begin
          Rec_Position := True;
          SetBarHeight;
          top := Cur_Top;
          Bottom := Cur_Bottom;
        end
        else
          Rec_Position := False;
        Timer1.Enabled := FAnchors <> [];
    
      end;
    end;
    
    procedure TForm3.Button1Click(Sender: TObject);
    var
      c:TComponent;
      s:string;
    begin
      s:='01';
      c:= FindComponent('Image'+s);
                Clipboard.Assign(TImage(c).Picture);
                RxRichEdit1.PasteFromClipboard;
    end;
    
    procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      if Assigned(RevDataThread) then FreeAndNil(RevDataThread);
      IdTCPClient1.Disconnect;
    end;
    
    procedure TForm3.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    begin
      CanClose := False;
      RzButton3.Click;
    end;
    
    procedure TForm3.FormCreate(Sender: TObject);
    begin
      Timer1.Enabled := False;
      Timer1.Interval := 200;
      //FormStyle := fsStayOnTop;
      BoolEnable:= False;
      RzListBox1.Clear;
      UnLcokTimes :=0;
      LockStatus := False;
      RxRichEdit1.Paragraph.LineSpacingRule:=lsSpecified;
      RxRichEdit1.Paragraph.LineSpacing:=20;
      ScrollBox1.VertScrollBar.Position :=0;
    end;
    
    procedure TForm3.FormMouseEnter(Sender: TObject);
    begin
      RzTrayIcon1.Animate := False;
      RzTrayIcon1.IconIndex := 0;
    end;
    
    procedure TForm3.Timer1Timer(Sender: TObject);
    const
      cOffset = 2;
    begin
      if MousePosion then
      begin
        if akLeft in FAnchors then
          Left := 0;
        if akTop in FAnchors then
          top := 0;
        if akRight in FAnchors then
          Left := Screen.Width - Width;
        if akBottom in FAnchors then
          top := Screen.Height - Height;
      end
      else
      begin
        if akLeft in FAnchors then
        begin
          Left := -Width + cOffset;
          SetBarHeight;
          top := Cur_Top;
          Height := Cur_Bottom;
        end;
        if akTop in FAnchors then
          top := -Height + cOffset;
        if akRight in FAnchors then
        begin
          Left := Screen.Width - cOffset;
          SetBarHeight;
          top := Cur_Top;
          Height := Cur_Bottom;
        end;
        if akBottom in FAnchors then
          top := Screen.Height - cOffset;
      end;
    
    end;
    
    procedure TForm3.Timer2Timer(Sender: TObject);
    var
      buf:TDataPack;
      bbyte:TIdBytes;
    begin
      FillChar(buf,SizeOf(TDataPack),'');
      buf.Command := CltTimer;
      BByte := RawToBytes(buf, SizeOf(TDataPack));
      try
        IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
      except
        Timer2.Enabled := False;
        RzAnimator1.Animate := False;
        RzAnimator1.ImageIndex :=1;
        ShowMessage('与服务器断开连接');
      end;
    end;
    
    procedure TForm3.Timer3Timer(Sender: TObject);
    begin
      if not MouseInScrollBox  then
      begin
        if ScrollBox1.Visible  then ScrollBox1.Visible := False;
      end;
      Timer3.Enabled := ScrollBox1.Visible;
    end;
    
    procedure TForm3.IdTCPClient1Connected(Sender: TObject);
    //var
    //  BByte: TIdBytes;
    //  buf: TDataPack;
    begin
    //  FillChar(buf, SizeOf(TDataPack), '');
    //  buf.Command := CltConnect;
    //  buf.CltInfo.CltName := 'ZZPC';
    //  BByte := RawToBytes(buf, SizeOf(TDataPack));
    //  IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
    //  if Assigned(RevDataThread)  then RevDataThread.Terminate;
    
    end;
    
    procedure TForm3.IdTCPClient1Disconnected(Sender: TObject);
    begin
      if Assigned(RevDataThread)  then RevDataThread.Terminate;
      RzListBox1.Items.Clear;
      RzEdit2.ReadOnly := False;
      RzToolButton1.Enabled := False;
      RzButton4.Enabled := False;
      RzCheckBox1.Checked := False;
    end;
    
    
    procedure TForm3.Image01Click(Sender: TObject);
    var
      s:String;
    begin
      s:=RightStr(TImage(Sender).Name,2);
      RzMemo2.Text := '['+s+']';
      ScrollBox1.Visible := False;
      RzToolButton1.Click;
    end;
    
    procedure TForm3.Image1Click(Sender: TObject);
    begin
      ScrollBox1.Visible := not ScrollBox1.Visible;
      Timer3.Enabled := ScrollBox1.Visible;
    end;
    
    procedure TForm3.Image2Click(Sender: TObject);
    begin
      if FontDialog1.Execute then  RxRichEdit1.Font := FontDialog1.Font;
    
    end;
    
    procedure TForm3.LabeledEdit1KeyPress(Sender: TObject; var Key: Char);
    begin
      if ((Key = #13) and (((hi(GetKeyState(VK_CONTROL))) and $80) <> $80))  then
      begin
        Key :=#0;
        RzButton3.Click;
      end;
    end;
    
    function TForm3.MouseInScrollBox: Boolean;
    begin
      Result := False;
      if WindowFromPoint(Mouse.CursorPos) = ScrollBox1.Handle then Result := True;
    end;
    
    function TForm3.MousePosion: Boolean;
    begin
      Result := False;
      if (WindowFromPoint(Mouse.CursorPos) = Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzListBox1.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzPanel1.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzPanel2.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RxRichEdit1.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzMemo2.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzCheckBox1.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzEdit1.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzEdit2.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzEdit3.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzAnimator1.Handle)  or
        (WindowFromPoint(Mouse.CursorPos) = RzButton2.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzButton3.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzSplitter1.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzSplitter2.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = LabeledEdit1.Handle)  or
        (WindowFromPoint(Mouse.CursorPos) = RzButton4.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzButton5.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = RzPanel3.Handle) or
        (WindowFromPoint(Mouse.CursorPos) = ScrollBox1.Handle) then
        Result := True;
    end;
    
    procedure TForm3.N1Click(Sender: TObject);
    begin
      RzButton5.Click;
    end;
    
    procedure TForm3.N4Click(Sender: TObject);
    begin
      RzButton3.Click;
    end;
    
    procedure TForm3.PopupMenu1Popup(Sender: TObject);
    begin
      N3.Visible :=RzButton3.Caption = '锁定';
      N4.Visible := RzButton3.Caption = '锁定';
    end;
    
    procedure TForm3.RevCustMsg(var Msg: TMessage);
    var
      s:string;
      buf:TDataPack;
    begin
      FillChar(buf,SizeOf(TDataPack),'');
      s:=string(PDatapack(Pointer(msg.LParam))^.Data);
      form1.RzMemo1.Lines.Add(s);
    end;
    
    procedure TForm3.RxRichEdit1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    begin
      if RzTrayIcon1.Animate  then
      begin
        RzTrayIcon1.Animate := False;
        RzTrayIcon1.IconIndex := 0;
      end;
    end;
    
    procedure TForm3.RxRichEdit1URLClick(Sender: TObject; const URLText: string;
      Button: TMouseButton);
    begin
      ShellExecute(Application.Handle, nil, PChar(URLText), nil, nil, SW_SHOWNORMAL);
    end;
    
    procedure TForm3.RzButton1Click(Sender: TObject);
    var
      buf:TDataPack;
      Bbyte:TIdBytes;
      s,tm,bm:string;
      pt:TPoint;
      ctl:TComponent;
    begin
      if Trim(RzMemo2.Text) <>'' then
      begin
        if RzListBox1.ItemIndex <> -1 then
        begin
          s:=RzListBox1.SelectedItem;
          if s= form3.RzEdit2.Text then
          begin
            RzListBox1.CustomHint.Title :='提示';
            RzListBox1.CustomHint.Description :='您不能跟自己聊天,那是欲魔行为!';
            pt.X :=RzListBox1.Width div 2;
            pt.Y :=RzListBox1.Height div 6;
            RzListBox1.CustomHint.ImageIndex :=1;
            RzListBox1.CustomHint.HideAfter :=5000;
            RzListBox1.CustomHint.ShowHint(RzListBox1.ClientToScreen(pt));
            Exit;
          end;
    
          FillChar(buf, SizeOf(TDataPack), '');
          buf.Command := CltSendMessage;
          StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
          StrCopy(@buf.DstInfo.CltName, PChar(Encrystrings(s)));
          tm:= RzMemo2.Text + '   (' +datetimetostr(Now)+ ')';
          StrCopy(@buf.Data, PChar(Encrystrings(tm)));
          BByte := RawToBytes(buf, SizeOf(TDataPack));
          try
            IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
            if CheckBmp(tm) then
            begin
              bm := Copy(tm,2,2);
              RxRichEdit1.Lines.Add('你对 ' +RzListBox1.SelectedItem + ' 说:');
              ctl:= FindComponent('Image'+bm);
              //ShowMessage(TImage(ctl).Name);
              if ctl <> nil then
              begin
                Clipboard.Assign(TImage(ctl).Picture);
                RxRichEdit1.PasteFromClipboard;
              end;
            end else RxRichEdit1.Lines.Add('你对 '+ RzListBox1.SelectedItem + '说: '+ tm);
            PostMessage(RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
            RzMemo2.Clear;
          except
    //        if not  IdTCPClient1.IOHandler.Opened  then
    //        begin
              ShowMessage('已与服务器断开连接,消息发送不成功');
              RzListBox1.Items.Clear;
              RzEdit2.ReadOnly := False;
              RzToolButton1.Enabled := False;
              RzButton4.Enabled := False;
              RzCheckBox1.Checked := False;
    //        end;
    
          end;
        end  else begin
          RzListBox1.CustomHint.Title :='提示';
          RzListBox1.CustomHint.Description :='请在这里选择一个聊天对象';
          pt.X :=RzListBox1.Width div 2;
          pt.Y :=RzListBox1.Height div 6;
          RzListBox1.CustomHint.ImageIndex :=1;
          RzListBox1.CustomHint.HideAfter :=3000;
          RzListBox1.CustomHint.ShowHint(RzListBox1.ClientToScreen(pt));
        end;
      end else begin
        RzMemo2.CustomHint.Title :='提示';
        RzMemo2.CustomHint.Description :='不能发送空消息哦';
        pt.X :=RzMemo2.Width div 2;
        pt.Y :=RzMemo2.Height div 2;
        RzMemo2.CustomHint.ImageIndex :=0;
        RzMemo2.CustomHint.HideAfter :=2000;
        RzMemo2.CustomHint.ShowHint(RzMemo2.ClientToScreen(pt));
      end;
    end;
    
    procedure TForm3.RzButton2Click(Sender: TObject);
    begin
      RxRichEdit1.Clear;
    end;
    
    procedure TForm3.RzButton3Click(Sender: TObject);
    var
      pt:TPoint;
      buf:TDataPack;
      Bbyte:TIdBytes;
    begin
      if RzButton3.Caption = '锁定' then
      begin
        FillChar(buf, SizeOf(TDataPack), '');
        buf.Command := CltLockSrc;
        StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
        BByte := RawToBytes(buf, SizeOf(TDataPack));
        try
          try
            IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
          except
            //
          end;
        finally
          RxRichEdit1.Visible := False;
          RzMemo2.Visible := False;
          RzListBox1.Visible := False;
          RzToolButton1.Visible := False;
          RzButton4.Visible := False;
          RzButton2.Visible := False;
          RzCheckBox1.Visible := False;
          RzLabel5.Visible := False;
          RzEdit3.Visible := False;
          RzTrayIcon1.MinimizeApp;
          RzButton3.Caption :='解锁';
          LabeledEdit1.Visible := True;
          RzLabel1.Visible := False;
          RzLabel2.Visible := False;
          RzEdit1.Visible := False;
          RzEdit2.Visible := False;
          RzPanel3.Visible := False;
          LabeledEdit1.SetFocus;
          LockStatus :=True;     //屏幕锁定状态
          ScrollBox1.Visible := False;
        end;
    //    except
    //      RzButton3.CustomHint.Title :='错误';
    //      RzButton3.CustomHint.Description :='锁屏失败,请重试';
    //      pt.X :=RzButton3.Width div 2;
    //      pt.Y :=RzButton3.Height div 2;
    //      RzButton3.CustomHint.ImageIndex :=1;
    //      RzButton3.CustomHint.HideAfter :=3000;
    //      RzButton3.CustomHint.ShowHint(RzButton3.ClientToScreen(pt));
    //    end;
      end else begin
          if LabeledEdit1.Text = UnLockString then
          begin
            FillChar(buf, SizeOf(TDataPack), '');
            buf.Command := CltUnlockSrc;
            StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
            BByte := RawToBytes(buf, SizeOf(TDataPack));
            try
              try
                IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
              except
                //
              end;
            finally
              UnLcokTimes :=0;
              RxRichEdit1.Visible := True ;
              RzMemo2.Visible := True ;
              RzListBox1.Visible := True ;
              RzToolButton1.Visible := True ;
              RzButton4.Visible := True;
              RzButton2.Visible := True ;
              RzCheckBox1.Visible := True;
              RzPanel3.Visible := True;
              RzButton3.Caption :='锁定';
              LabeledEdit1.Text :='';
              LabeledEdit1.Visible := False;
              if not RzCheckBox1.Checked  then
              begin
                RzLabel5.Visible := True;
                RzEdit3.Visible := True;
                RzLabel1.Visible := True;
                RzLabel2.Visible := True;
                RzEdit1.Visible := True;
                RzEdit2.Visible := True;
                RzPanel3.Visible := False;
              end;
              LockStatus := False;   //屏幕锁定状态
    //          RzButton3.CustomHint.Title :='错误';
    //          RzButton3.CustomHint.Description :='解锁失败,请重试';
    //          pt.X :=RzButton3.Width div 2;
    //          pt.Y :=RzButton3.Height div 2;
    //          RzButton3.CustomHint.ImageIndex :=1;
    //          RzButton3.CustomHint.HideAfter :=3000;
    //          RzButton3.CustomHint.ShowHint(RzButton3.ClientToScreen(pt));
            end;
          end else begin
            UnLcokTimes := UnLcokTimes+1;
            LabeledEdit1.Text :='';
            LabeledEdit1.CustomHint.Title :='错误';
            LabeledEdit1.CustomHint.Description :='解锁密码不正确';
            pt.X :=LabeledEdit1.Width div 2;
            pt.Y :=LabeledEdit1.Height div 2;
            LabeledEdit1.CustomHint.ImageIndex :=0;
            LabeledEdit1.CustomHint.HideAfter :=2000;
            LabeledEdit1.CustomHint.ShowHint(LabeledEdit1.ClientToScreen(pt));
            LabeledEdit1.SetFocus;
            if UnLcokTimes >=3 then
            begin
              ShowMessage('解锁密码尝试3次均不正确,程序退出');
              if IdTCPClient1.Connected  then  IdTCPClient1.Disconnect;
              if Assigned(RevDataThread ) then RevDataThread.Terminate;
              Close;
            end;
          end;
      end;
    end;
    
    procedure TForm3.RzButton4Click(Sender: TObject);
    var
      buf:TDataPack;
      Bbyte:TIdBytes;
      s:string;
      pt:TPoint;
    begin
      if RzListBox1.ItemIndex <>-1 then
      begin
        FillChar(buf, SizeOf(TDataPack), '');
        s:=RzListBox1.SelectedItem;
        StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
        StrCopy(@buf.DstInfo.CltName, PChar(Encrystrings(s)));
        buf.Command :=CltClear;
        BByte := RawToBytes(buf, SizeOf(TDataPack));
        try
          IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
          RxRichEdit1.CustomHint.Title :='提示';
          RxRichEdit1.CustomHint.Description :='您已清除自己和对方聊天记录';
          pt.X :=RxRichEdit1.Width div 2;
          pt.Y :=RxRichEdit1.Height div 2;
          RxRichEdit1.CustomHint.ImageIndex :=1;
          RxRichEdit1.CustomHint.HideAfter :=8000;
          RxRichEdit1.CustomHint.ShowHint(RxRichEdit1.ClientToScreen(pt));
          RxRichEdit1.Clear;
        except
          ShowMessage('已与服务器断开连接,清除屏幕不成功');
          RzListBox1.Items.Clear;
          RzEdit2.ReadOnly := False;
          RzToolButton1.Enabled := False;
          RzButton4.Enabled := False;
          RzCheckBox1.Checked := False;
        end;
      end else begin
          RzListBox1.CustomHint.Title :='提示';
          RzListBox1.CustomHint.Description :='请在这里选择一个清除屏幕对象';
          pt.X :=RzListBox1.Width div 2;
          pt.Y :=RzListBox1.Height div 6;
          RzListBox1.CustomHint.ImageIndex :=1;
          RzListBox1.CustomHint.HideAfter :=3000;
          RzListBox1.CustomHint.ShowHint(RzListBox1.ClientToScreen(pt));
      end;
    
    end;
    
    procedure TForm3.RzButton5Click(Sender: TObject);
    begin
      Application.Terminate;
    end;
    
    procedure TForm3.RzCheckBox1Click(Sender: TObject);
    var
      pt:TPoint;
    begin
      IdTCPClient1.Host := RzEdit1.Text;
      if RzEdit3.Text <>'' then IdTCPClient1.Port := StrToInt(RzEdit3.Text)
      else begin
        RzEdit3.CustomHint.Title :='提示';
        RzEdit3.CustomHint.Description :='服务器端口不能为空';
        pt.X :=RzEdit3.Width div 2;
        pt.Y :=RzEdit3.Height div 2;
        RzEdit3.CustomHint.ImageIndex :=0;
        RzEdit3.CustomHint.HideAfter :=2000;
        RzEdit3.CustomHint.ShowHint(RzEdit3.ClientToScreen(pt));
        RzCheckBox1.Checked := False;
        Exit;
      end;
      if (RzEdit2.Text ='') then
      begin
        RzEdit2.CustomHint.Title :='提示';
        RzEdit2.CustomHint.Description :='聊天昵称不能为空';
        pt.X :=RzEdit2.Width div 2;
        pt.Y :=RzEdit2.Height div 2;
        RzEdit2.CustomHint.ImageIndex :=0;
        RzEdit2.CustomHint.HideAfter :=2000;
        RzEdit2.CustomHint.ShowHint(RzEdit2.ClientToScreen(pt));
        RzCheckBox1.Checked := False;
        Exit;
      end;
      if Pos(' ',RzEdit2.Text)<>0 then
      begin
        RzEdit2.CustomHint.Title :='提示';
        RzEdit2.CustomHint.Description :='聊天昵称中不能包含空格和 | 字符';
        pt.X :=RzEdit2.Width div 2;
        pt.Y :=RzEdit2.Height div 2;
        RzEdit2.CustomHint.ImageIndex :=0;
        RzEdit2.CustomHint.HideAfter :=2000;
        RzEdit2.CustomHint.ShowHint(RzEdit2.ClientToScreen(pt));
        RzCheckBox1.Checked := False;
        Exit;
      end;
      if (RzEdit1.Text ='') then
      begin
        RzEdit1.CustomHint.Title :='提示';
        RzEdit1.CustomHint.Description :='服务器地址不能为空';
        pt.X :=RzEdit1.Width div 2;
        pt.Y :=RzEdit1.Height div 2;
        RzEdit1.CustomHint.ImageIndex :=0;
        RzEdit1.CustomHint.HideAfter :=2000;
        RzEdit1.CustomHint.ShowHint(RzEdit1.ClientToScreen(pt));
        RzCheckBox1.Checked := False;
        Exit;
      end;
      try
        if  RzCheckBox1.Checked  then
        begin
          IdTCPClient1.Connect;
          RevDataThread := TRevDataThread.Create(True);
          RevDataThread.FreeOnTerminate := True;
          RevDataThread.Start;
          RzToolButton1.Enabled := True;
          RzButton4.Enabled := True;
          RzCheckBox1.Checked := True;
          RzEdit2.ReadOnly := True;
          Timer2.Enabled := True;
          RzEdit3.Visible := False;
          RzLabel5.Visible := False;
          RzLabel1.Visible := False;
          RzLabel2.Visible := False;
          RzPanel3.Visible := True;
          RzEdit1.Visible := False;
          RzEdit2.Visible := False;
          RzAnimator1.Animate := True;
        end
        else
        begin
          IdTCPClient1.Disconnect;
          if Assigned(RevDataThread)  then  RevDataThread.Terminate;
          RzCheckBox1.Checked := False;
          RzToolButton1.Enabled :=False;
          RzButton4.Enabled := False;
          RzEdit2.ReadOnly := False;
          Timer2.Enabled := False;
          RzEdit3.Visible := True;
          RzLabel5.Visible := True;
          RzLabel1.Visible := True;
          RzLabel2.Visible := True;
          RzPanel3.Visible := False;
          RzEdit1.Visible := True;
          RzEdit2.Visible := True;
          RzAnimator1.Animate := False;
          RzAnimator1.ImageIndex :=1;
        end;
      except
        RzEdit2.ReadOnly := False;
        RzCheckBox1.Checked := False;
        RzToolButton1.Enabled :=False;
        RzButton4.Enabled := False;
        if Assigned(RevDataThread)  then  RevDataThread.Terminate;
        if IdTCPClient1.Connected then IdTCPClient1.Disconnect;
        ShowMessage('连接服务器失败,请确认服务器地址是否正确');
      end;
    end;
    
    procedure TForm3.RzEdit1KeyPress(Sender: TObject; var Key: Char);
    var
      tmp: string;
    begin
      tmp := '0123456789.' + Char(VK_BACK) + Char(VK_DELETE);
      if Pos(Key, tmp) = 0 then Key := #0;
    end;
    
    procedure TForm3.RzEdit3KeyPress(Sender: TObject; var Key: Char);
    var
      tmp: string;
    begin
      tmp := '0123456789' + Char(VK_BACK) + Char(VK_DELETE);
      if Pos(Key, tmp) = 0 then Key := #0;
    end;
    
    procedure TForm3.RzListBox1DblClick(Sender: TObject);
    begin
    //  form1.Show;
    end;
    
    procedure TForm3.RzListBox1MouseEnter(Sender: TObject);
    begin
      if RzTrayIcon1.Animate  then
      begin
        RzTrayIcon1.Animate := False;
        RzTrayIcon1.IconIndex := 0;
      end;
    end;
    
    
    
    procedure TForm3.RzMemo2KeyPress(Sender: TObject; var Key: Char);
    begin
      if (Key = #13)   then
      begin
        if (((hi(GetKeyState(VK_CONTROL))) and $80) <> $80) and n2.Checked then
        begin
          Key :=#0;
          if RzToolButton1.Enabled  then RzToolButton1.Click;
        end;
      end;
    end;
    
    procedure TForm3.RzMemo2MouseEnter(Sender: TObject);
    begin
      if RzTrayIcon1.Animate  then
      begin
        RzTrayIcon1.Animate := False;
        RzTrayIcon1.IconIndex := 0;
      end;
    end;
    
    
    procedure TForm3.RzSpinButtons1DownLeftClick(Sender: TObject);
    begin
      if RzPanel3.Height > 40 then  RzPanel3.Height := (RzPanel3.Height -4) div 3;
    end;
    
    procedure TForm3.RzSpinButtons1UpRightClick(Sender: TObject);
    begin
      if RzPanel3.Height <40 then RzPanel3.Height := RzPanel3.Height *3 +4;
    end;
    
    procedure TForm3.RzTrayIcon1MinimizeApp(Sender: TObject);
    begin
      BoolEnable:= True;
    end;
    
    procedure TForm3.RzTrayIcon1RestoreApp(Sender: TObject);
    begin
      BoolEnable:= False;
      RzTrayIcon1.Animate:= False;
      RzTrayIcon1.IconIndex := 0;
    end;
    
    procedure TForm3.SetBarHeight;
    var
      AppBarData: TAPPBARDATA;
    begin
      AppBarData.cbSize := SizeOf(AppBarData);
      If SHAppBarMessage(ABM_GETSTATE, AppBarData) AND (ABS_AUTOHIDE) <> 0 then
      begin
        Cur_Top := 1;
        Cur_Bottom := Screen.Height - 1;
      end
      else
      begin
        SHAppBarMessage(ABM_GETTASKBARPOS, AppBarData);
        case AppBarData.uEdge of
          ABE_TOP:
            begin
              Cur_Top := AppBarData.rc.Bottom + 1;
              Cur_Bottom := Screen.Height - 1;
            end;
          ABE_LEFT:
            begin
              Cur_Top := 1;
              Cur_Bottom := Screen.Height - 1;
            end;
          ABE_RIGHT:
            begin
              Cur_Top := 1;
              Cur_Bottom := Screen.Height - 1;
            end;
          ABE_BOTTOM:
            begin
              Cur_Top := 1;
              Cur_Bottom := Screen.Height -
                (AppBarData.rc.Bottom - AppBarData.rc.top) - 1;
            end;
        end;
      end;
    end;
    
    procedure TForm3.wmsizing(var Msg: TMessage);
    begin
      inherited;
      if (akRight in FAnchors) then
      begin
        with PRect(Msg.LParam)^ do
        begin
          Left := Screen.Width - Width;
          top := Cur_Top;
          Right := Screen.Width;
          Bottom := Cur_Bottom
        end;
      end
      else if (akLeft in FAnchors) then
      begin
        with PRect(Msg.LParam)^ do
        begin
          Left := 0;
          top := Cur_Top;
          Right := Width;
          Bottom := Cur_Bottom;
        end;
      end;
    end;
    
    { TRevDataThread }
    
    procedure TRevDataThread.AddCltList;
    var
      t,s:string;
      List:TStringList;
      OldCount,NewCount:Integer;
    begin
      list:= TStringList.Create;
      OldCount := Form3.RzListBox1.Count;
      Form3.RzListBox1.Clear;
      t:= string(buf.Data);
    //  count:=0;                     // dak|dkej|dinna|
    //  for i:= 0 to strlen(pchar(s)) do if copy(s,i,1)='|' then count:=count+1;  //计算字符串中包含几个分隔符 |
    //  for I := 0 to Count do
    //  begin
    //    ss:= LeftStr(s,Pos('|',s)-1);
    //  end;
      s:= Uncrystrings(t);
      s:=LeftStr(s,StrLen(PChar(s))-1);
      List.Delimiter:='|';
      List.DelimitedText:=s;
      //Form3.RzTrayIcon1.Hint := List.Text;
      Form3.RzListBox1.Items.Assign(list);
      NewCount := form3.RzListBox1.Count;
      List.Free;
      if NewCount > OldCount  then form3.RzTrayIcon1.ShowBalloonHint('提示','有用户登录',bhiInfo,10)
      else if NewCount < OldCount then form3.RzTrayIcon1.ShowBalloonHint('提示','有用户下线',bhiInfo,10);
    end;
    
    procedure TRevDataThread.AddMessage;
    var
      ss:string;
    begin
      ss:= DecryStr(UncrypKey(string(buf.CltInfo.CltName),TKey),mkey);
      case buf.Command  of
        CltLockSrc: Form3.RxRichEdit1.Lines.Add(ss + ' 锁定了屏幕');
    
        CltUnlockSrc : Form3.RxRichEdit1.Lines.Add(ss + ' 解锁了屏幕');
      end;
      PostMessage(Form3.RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
    end;
    
    procedure TRevDataThread.ClearScr;
    var
      pt:TPoint;
      ss:string;
    begin
      Form3.RxRichEdit1.Clear;
      ss:= Uncrystrings(string(buf.CltInfo.CltName));
      Form3.RxRichEdit1.CustomHint.Title :='提示';
      Form3.RxRichEdit1.CustomHint.Description := ss+' 清除了您的聊天记录';
      pt.X :=Form3.RxRichEdit1.Width div 2;
      pt.Y :=Form3.RxRichEdit1.Height div 2;
      Form3.RxRichEdit1.CustomHint.ImageIndex :=1;
      Form3.RxRichEdit1.CustomHint.HideAfter :=8000;
      Form3.RxRichEdit1.CustomHint.ShowHint(Form3.RxRichEdit1.ClientToScreen(pt));
      Form3.RxRichEdit1.Clear;
      Form3.RxRichEdit1.Lines.Add(ss+' 清除了您的聊天记录');
    end;
    
    procedure TRevDataThread.CltMessageIn;
    var
      s:string;
    begin
      s:= Uncrystrings(string(buf.CltInfo.CltName));
      form3.RxRichEdit1.Lines.Add(s + ' 可能离开,TA的屏幕是锁定状态') ;
      PostMessage(Form3.RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
    end;
    
    procedure TRevDataThread.DoDiscnt;
    begin
      form3.RzCheckBox1.Checked := False;
      Form3.IdTCPClient1.Disconnect;
      ShowMessage(Form3.RzEdit2.Text +' 已经存在,请更名重新登录');
    end;
    
    procedure TRevDataThread.DoSrvCloseQuery;
    begin
      Form3.IdTCPClient1.Disconnect;
      Form3.RzCheckBox1.Checked := False;
    end;
    
    procedure TRevDataThread.DoSrvMessage;
    var
      nr,ds:string;
    begin
      nr:=Uncrystrings(string(buf.Data));
      ds:= Uncrystrings(string(buf.DstInfo.CltName));
      Form3.RxRichEdit1.Lines.Add('[服务器消息]:您发送给 ['+ ds +'] 的消息: “'+ nr +'",转发不成功,请重新发送');
      PostMessage(Form3.RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
    end;
    
    procedure TRevDataThread.Execute;
    var
      BByte: TIdBytes;
      Nc:string;
    begin
      inherited;
      FillChar(buf, SizeOf(TDataPack), '');
      buf.Command := CltConnect;
      Nc := Encrystrings(form3.RzEdit2.Text);
      StrCopy(@buf.CltInfo.CltName, PChar(Nc));
      BByte := RawToBytes(buf, SizeOf(TDataPack));
      Form3.IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
      while (not Terminated) and (Form3.IdTCPClient1.Connected) do
      begin
        FillChar(buf, SizeOf(TDataPack), '');
        Form3.IdTCPClient1.IOHandler.ReadBytes(BByte, SizeOf(TDataPack), False);
        BytesToRaw(BByte, buf, SizeOf(TDataPack));
        case buf.Command of
          CltSendMessage:
            begin
              //SendMessage(Handle,CustMsg,CltSendMessage,Integer(PDataPack(buf)));
              Synchronize(showmsg);
              if LockStatus  then
              begin
                buf.DstInfo.CltName := buf.CltInfo.CltName;
                buf.Command := CltMessage;
                StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
                BByte := RawToBytes(buf, SizeOf(TDataPack));
                Form3.IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
              end;
            end;
          CltList :                   Synchronize(AddCltList);
    
          CltDisconnect :             Synchronize(DoDiscnt);
    
          CltTimer :  ;
    
          CltClear :                  Synchronize(clearscr);
    
          CltLockSrc,CltUnlockSrc  :  Synchronize(Addmessage);
    
          CltMessage :                Synchronize(cltmessageIn);
    
          SrvMessage :                Synchronize(DoSrvMessage);
    
          SrvCloseQuery :             Synchronize(DoSrvCloseQuery);
        end;
      end;
    end;
    
    procedure TRevDataThread.ShowMsg;
    var
      s,ss,bm:string;
      ctl:TComponent;
    begin
      s:=Uncrystrings(string(buf.Data));
      ss:= Uncrystrings(string(buf.CltInfo.CltName));
      if CheckBmp(s) then
      begin
        bm := Copy(s,2,2);
        Form3.RxRichEdit1.Lines.Add(ss + ' 对你说:');
        //Clipboard.Assign(form3.Image1.Picture);
        ctl:= Form3.FindComponent('Image'+bm);
        if ctl <> nil then
        begin
          Clipboard.Assign(TImage(ctl).Picture);
          form3.RxRichEdit1.PasteFromClipboard;
        end;
      end else Form3.RxRichEdit1.Lines.Add(ss + ' 对你说:'+s );
      PostMessage(Form3.RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
      if BoolEnable or ((form3.Timer1.Enabled) and (not form3.MousePosion))  then
      begin
        if not Form3.RzTrayIcon1.Animate then Form3.RzTrayIcon1.Animate:=True;
      end;
    
    end;
    
    end.
    

      公共单元

    unit Unit2;
    
    interface
    
    uses Windows,Messages,Classes,SysUtils,StrUtils;
    
     const CustMsg = WM_USER + 2110;
           CltConnect = 1;
           CltDisconnect =2;
           CltSendMessage =3;
           CltList=4;
           CltTimer =5;
           CltClear = 6;
           CltLockSrc =7;
           CltUnlockSrc = 8;
           CltMessage    = 9;
           SrvMessage  =10;
           SrvTimer =11;
           SrvCloseQuery =12;
           DataSize = 1024 *5;     //数据缓冲区大小
           UnLockString = '123456';
     type
      TCltInfo = packed record
        CltIP:array[0..14] of Char;
        CltName:array[0..255] of Char;
      end;
    
      TDataPack = record
        CltInfo:TCltInfo;
        DstInfo:TCltInfo;
        Command:Integer;
        Data:array[0..DataSize -1] of Char;
      end;
    
      PDataPack = ^TDataPack;
    function Encrystrings(str:string):string;
    function Uncrystrings(str:string):string;
    function EncrypKey(Src: String; Key: String): string;
    function UncrypKey(Src: String; Key: String): string;
    function GetTMkey:string;
    function CheckBmp(Str:string):Boolean;
    var
      UnLcokTimes:Integer;
      LockStatus:Boolean;
    implementation
      uses Unit4;
    
    function CheckBmp(Str:string):Boolean;
    begin
      Result := False;
      if Length(Str) < 4 then  Exit;
      if (LeftStr(Str,1) ='[') and (Copy(Str,4,1) = ']') then Result :=True;
    end;
    function Encrystrings(str:string):string;
    var
      tmp:string;
    begin
      tmp := EncryStr(str,MKey);
      Result := EncrypKey(tmp,TKey);
    end;
    
    function Uncrystrings(str:string):string;
    var
      tmp:string;
    begin
      tmp:= UncrypKey(str,TKey);
      Result := DecryStr(tmp,MKey);
    end;
    // 加密函数
    function EncrypKey(Src: String; Key: String): string;
    var
      KeyLen: integer;
      KeyPos: integer;
      offset: integer;
      dest: string;
      SrcPos: integer;
      SrcAsc: integer;
      Range: integer;
    begin
      //此处省略,自己写
    end;
    
    // 解密函数
    function UncrypKey(Src: String; Key: String): string;
    var
      //idx: integer;
      KeyLen: integer;
      KeyPos: integer;
      offset: integer;
      dest: string;
      SrcPos: integer;
      SrcAsc: integer;
      TmpSrcAsc: integer;
    begin
     //此处省略,自己写
    end;
    
    function GetTMkey:string;
    var
      ss: string;
      n: Integer;
    begin
      ss := '';
      Randomize;
      repeat
        n := Random(127);
        if n>=34 then ss := ss + char(n);
      until (Length(ss)>=12);
      Result  := ss;
    end;
    end.
    

      

      

  • 相关阅读:
    云风版协程库源代码分析
    取消勾选use androidx.* artifacts
    Linux编程之信号
    Linux编程之错误代码
    git身份验证失败清除密码缓存
    实现可执行的so动态链接库
    同步以及异步connect
    STM32系列芯片命名规范
    QtAV的编译方法
    汇编文件后缀 .s 与 .S
  • 原文地址:https://www.cnblogs.com/mengmianren/p/4647960.html
Copyright © 2011-2022 走看看