【问题标题】:Delphi 7: Handling events in console application (TidIRC)Delphi 7:在控制台应用程序中处理事件(TidIRC)
【发布时间】:2012-07-07 01:03:41
【问题描述】:

我正在尝试基于 Indy 的 IRC 组件 (TIdIRC) 制作控制台应用程序,但我遇到了事件问题。这是我的代码:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Classes,
  Math,
  IdBaseComponent,
  IdComponent,
  IdTCPConnection,
  IdTCPClient,
  IdIRC;

type
  TEvents = class
  public
    procedure Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);
  end;

const
  IrcServ = 'gr.irc.gr';
  IrcPort = 6667;
  IrcChan = '#lalala';

var
  Irc: TidIRC;
  Event: TEvents;
  uName, rName: string;

function Log(s: string): string;
var now: TDateTime;
begin
  now := Time;
  result := FormatDateTime('[hh:nn:ss] ', now) + s;
end;

procedure TEvents.Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);
begin
  Log(AUser.Nick+' '+ACommand+' '+AContent);
end;

begin
  Event := TEvents.Create;
  Irc := TidIRC.Create(nil);
  Irc.OnRaw := Event.Raw;
  Randomize;
  Write('Nickname: ');
  ReadLn(uName);
  rName := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
  with Irc do begin
    AltNick := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
    Nick := rName;
    Username := rName;
    RealName := 'I.D.M.';
    Host := IrcHost;
    Port := IrcPort;
    //MaxLineAction := maException;  <-- [ERROR] Undeclared identifier: 'maException'
    ReadTimeout := 0;
    UserMode := [];
    Connect();
    Join(IrcChan);
  end;
  ReadLn;

end.

到目前为止,我已经尝试了所有我能想到的方法,但是,虽然应用程序连接成功,但它不会返回任何原始消息......我错过了什么?

【问题讨论】:

    标签: delphi events delphi-7 console-application indy


    【解决方案1】:

    TdIRC 使用内部工作线程来接收数据。 OnRaw 事件在该线程解析数据时触发。该线程使用TThread.Synchronize() 进行解析。由于您的主线程没有活动的 VCL 消息循环,您可以手动抽取Synchronize() 队列。连接后,在连接到 IRC 时,循环调用 Classes 单元中的 CheckSynchronize() 函数,例如:

    begin 
      ...
      Connect; 
      try
        Join(IrcChan); 
        do
          CheckSynchronize;
          Sleep(10);
        until SomeCondition;
      finally
        Disconnect;
      end;
      ...  
    end. 
    

    为了更好地衡量,您可以在Classes 单元中为WakeMainThread 事件分配一个处理程序,以帮助控制何时应该调用CheckSynchronize(),这样主线程就可以在IRC 连接空闲时进入睡眠状态,例如:

    program Project1;     
    
    {$APPTYPE CONSOLE}     
    
    uses     
      SysUtils,     
      Classes,     
      Math,     
      IdBaseComponent,     
      IdComponent,     
      IdTCPConnection,     
      IdTCPClient,     
      IdIRC;     
    
    type     
      TEvents = class     
      private
        FSyncEvent: TEvent;
      public     
        constructor Create;
        destructor Destroy; override;
        procedure Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);     
        procedure Wake(Sender: TObject);
        procedure CheckSync;
      end;     
    
    function Log(s: string): string;      
    begin      
      result := FormatDateTime('[hh:nn:ss] ', Time) + s;      
    end;      
    
    constructor TEvents.Create;
    begin
      inherited;
      FSyncEvent := TEvent.Create(nil, False, False, '');
    end;
    
    destructor TEvents.Destroy;
    begin
      FSyncEvent.Free;
      inherited;
    end;
    
    procedure TEvents.Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);      
    begin      
      Log(AUser.Nick+' '+ACommand+' '+AContent);      
    end;      
    
    procedure TEvents.Wake(Sender: TObject);
    begin
      FSyncEvent.SetEvent;
    end;
    
    procedure TEvents.CheckSync;
    begin
      FSyncEvent.WaitFor(Infinite);
      CheckSynchronize;
    end;
    
    const     
      IrcServ = 'gr.irc.gr';     
      IrcPort = 6667;     
      IrcChan = '#lalala';     
    
    var      
      Irc: TidIRC;      
      Event: TEvents;      
      uName, rName: string;      
    
    begin
      Event := TEvents.Create;       
      try
        WakeMainThread := Event.Wake;
        Irc := TIdIRC.Create(nil);       
        try
          Irc.OnRaw := Event.Raw;       
          Randomize;       
          Write('Nickname: ');       
          ReadLn(uName);       
          rName := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;       
          with Irc do begin       
            AltNick := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
            Nick := rName;       
            Username := rName;       
            RealName := 'I.D.M.';       
            Host := IrcHost;       
            Port := IrcPort;       
            //MaxLineAction := maException;  <-- [ERROR] Undeclared identifier: 'maException'       
            ReadTimeout := 0;       
            UserMode := [];       
            Connect;       
            try
              Join(IrcChan);       
              do
                Event.CheckSync;
              until SomeCondition;
            finally
              Disconnect;
            end;
          end;       
        finally
          Irc.Free;
        end;
      finally
        Event.Free;
      end;
    end.
    

    【讨论】:

    • 感谢您的回复雷米。您是否可以用一些代码解释如何“泵送消息队列”?我在 idirc.pas 中找到的唯一线程是TIdIrcReadThread。我试图用项目中的自定义线程来捕捉它,但没有运气。
    • 控制台应用程序实际上是否有一个具有 ProcessMessages() 方法的应用程序?
    • @rudy 如果项目使用 Forms.pas,它会这样做。不过,那是可怕的矫枉过正。只需使用 while GetMessage(...) do begin TranslateMessage(...);调度消息(...);结尾;抽队列。
    • @David:确实矫枉过正。我永远不会在控制台应用程序中使用表单。
    • 其实现在想想,还有一个更简单的解决方案。在 D7 中,TThread.Synchronize() 将同步请求放入内存队列中,可以使用 Classes 单元中的 CheckSynchronize() 函数手动抽取该队列,根本不涉及任何消息循环。我已经更新了我的答案以反映这一点。
    猜你喜欢
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-08
    • 1970-01-01
    • 2011-09-05
    相关资源
    最近更新 更多