Delphi 7:在控制台应用程序(TidIRC)中处理事件

Delphi 7:在控制台应用程序(TidIRC)中处理事件,delphi,events,delphi-7,console-application,indy,Delphi,Events,Delphi 7,Console Application,Indy,我正在尝试基于Indy的IRC组件TIdIRC制作一个控制台应用程序,但我遇到了事件问题。这是我的密码: program Project1; {$APPTYPE CONSOLE} uses SysUtils, Classes, Math, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdIRC; type TEvents = class public procedur

我正在尝试基于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.
到目前为止,我已经尝试了我所能想到的一切,但是,尽管应用程序已成功连接,但它不会返回任何原始消息。。。我缺少什么?

TdIRC使用内部工作线程来接收数据。OnRaw事件在该线程解析数据时触发。线程使用TThread.Synchronize进行解析。由于主线程没有活动的VCL消息循环,因此可以手动泵送同步队列。连接后,在连接到IRC时,从循环中的类单元调用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.
TdIRC使用内部工作线程来接收数据。OnRaw事件在该线程解析数据时触发。线程使用TThread.Synchronize进行解析。由于主线程没有活动的VCL消息循环,因此可以手动泵送同步队列。连接后,在连接到IRC时,从循环中的类单元调用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。我试图在project中使用自定义线程捕获它,但没有成功。控制台应用程序是否确实有一个具有ProcessMessages方法的应用程序?@rudy如果项目使用Forms.pas,它会。不过,这太过分了。只需在获取消息时使用。。。开始翻译信息。。。;发送消息。。。;终止为了排起长队。@David:真是太过分了。我从来不会想到在控制台应用程序中使用表单。事实上,现在我想到了一个更简单的解决方案。在D7中,TThread.Synchronize将同步请求放入内存队列,该队列可以使用类单元中的CheckSynchronize函数手动抽取,而不涉及任何消息循环。我已经更新了我的答案来反映这一点。谢谢你的回复,雷米。您是否可以用一些代码解释如何泵送消息队列?我在idirc.pas中找到的唯一线程是TIdIrcReadThread。我试图在project中使用自定义线程捕获它,但没有成功。控制台应用程序是否确实有一个具有ProcessMessages方法的应用程序?@rudy如果项目使用Forms.pas,它会。不过,这太过分了。只需在获取消息时使用。。。开始翻译信息。。。;发送消息。。。;终止为了排起长队。@David:真是太过分了。我从来不会想到在控制台应用程序中使用表单。事实上,现在我想到了一个更简单的解决方案。在D7中,TThread.Synchronize将同步请求放入内存队列,该队列可以使用类单元中的CheckSynchronize函数手动抽取,而不涉及任何消息循环。我更新了我的答案以反映这一点。